Skip to content

Commit

Permalink
enhance display
Browse files Browse the repository at this point in the history
  • Loading branch information
dandyvica committed Jan 4, 2025
1 parent 52f5e2d commit 030e23b
Show file tree
Hide file tree
Showing 15 changed files with 294 additions and 105 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ byteorder = "1.5.0"
bytes = "1.5.0"
chrono = "0.4.38"
clap = "4.5.9"
colored = "2.1.0"
colored = "2.2.0"
enum_from = { git = "https://github.com/dandyvica/enum_from.git" }
handlebars = "6.2.0"
http = "1.0.0"
Expand All @@ -36,7 +36,7 @@ regex = "1.11.1"
reqwest = { version = "0.12.9", default-features = false, features = ["rustls-tls-webpki-roots", "blocking", "http2"] }
resolving = { git = "https://github.com/dandyvica/resolving" }
rustc_version_runtime = "0.3.0"
rustls = { version = "0.23.17", default-features = false, features = ["std", "tls12", "ring"] }
rustls = { version = "0.23.20", default-features = false, features = ["std", "tls12", "ring"] }
rustls-pki-types = "1.1.0"
serde = { version = "1.0.195", features = [ "derive" ] }
serde_json = { version = "1.0.111", features = ["preserve_order"] }
Expand Down
75 changes: 43 additions & 32 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ Caveat: all options starting with a dash (-) should be placed after optional [TY
.arg(
Arg::new("4")
.short('4')
.long("ip4")
.long("ipv4")
.long_help("Sets IP version 4. Only send queries to ipv4 enabled nameservers.")
.action(ArgAction::SetTrue)
.value_name("IPV4")
Expand All @@ -212,7 +212,7 @@ Caveat: all options starting with a dash (-) should be placed after optional [TY
.arg(
Arg::new("6")
.short('6')
.long("ip6")
.long("ipv6")
.long_help("Sets IP version 6. Only send queries to ipv6 enabled nameservers.")
.action(ArgAction::SetTrue)
.value_name("IPV6")
Expand Down Expand Up @@ -494,20 +494,20 @@ Caveat: all options starting with a dash (-) should be placed after optional [TY
.action(ArgAction::SetTrue)
.help_heading("Display options")
)
.arg(
Arg::new("no-add")
.long("no-add")
.long_help("Don't show the additional RR section. Showed by default.")
.action(ArgAction::SetTrue)
.help_heading("Display options")
)
.arg(
Arg::new("no-auth")
.long("no-auth")
.long_help("Don't show the authorative RR section. Showed by default.")
.action(ArgAction::SetTrue)
.help_heading("Display options")
)
// .arg(
// Arg::new("no-add")
// .long("no-add")
// .long_help("Don't show the additional RR section. Showed by default.")
// .action(ArgAction::SetTrue)
// .help_heading("Display options")
// )
// .arg(
// Arg::new("no-auth")
// .long("no-auth")
// .long_help("Don't show the authorative RR section. Showed by default.")
// .action(ArgAction::SetTrue)
// .help_heading("Display options")
// )
.arg(
Arg::new("no-colors")
.long("no-colors")
Expand Down Expand Up @@ -537,12 +537,19 @@ Caveat: all options starting with a dash (-) should be placed after optional [TY
.help_heading("Display options")
)
.arg(
Arg::new("show-opt")
.long("show-opt")
.long_help("If set, OPT record is displayed, if any.")
Arg::new("show-all")
.long("show-all")
.long_help("If set, show all sections: answer, authorative, additional.")
.action(ArgAction::SetTrue)
.help_heading("Display options")
)
// .arg(
// Arg::new("show-opt")
// .long("show-opt")
// .long_help("If set, OPT record is displayed, if any.")
// .action(ArgAction::SetTrue)
// .help_heading("Display options")
// )
.arg(
Arg::new("stats")
.long("stats")
Expand Down Expand Up @@ -699,6 +706,12 @@ Caveat: all options starting with a dash (-) should be placed after optional [TY
options.transport.ip_version = IPVersion::V6;
}

// when providing an IPV6 address using @ (ex: @2001:678:8::3) and not providing the -6 flag
// error occurs because by default, IPV4 is set. So in this case, reset to IPV6
if options.transport.endpoint.is_ipv6() {
options.transport.ip_version = IPVersion::V6;
}

//───────────────────────────────────────────────────────────────────────────────────
// recursion desired flag
//───────────────────────────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -818,21 +831,22 @@ Caveat: all options starting with a dash (-) should be placed after optional [TY
options.display.headers = matches.get_flag("headers");
options.display.json = matches.get_flag("json");
options.display.json_pretty = matches.get_flag("json-pretty");
options.display.no_additional = matches.get_flag("no-add");
options.display.no_authorative = matches.get_flag("no-auth");
options.display.question = matches.get_flag("question");
// options.display.no_additional = matches.get_flag("no-add");
// options.display.no_authorative = matches.get_flag("no-auth");
options.display.show_question = matches.get_flag("question");
options.display.raw_ttl = matches.get_flag("raw-ttl");
options.display.short = matches.get_flag("short");
options.display.show_opt = matches.get_flag("show-opt");
options.display.show_all = matches.get_flag("show-all");
//options.display.show_opt = matches.get_flag("show-opt");
options.display.stats = matches.get_flag("stats");
options.display.puny = matches.get_flag("puny");

// handlebars template
// if let Some(path) = matches.get_one::<PathBuf>("tpl") {
// // read handlebars file as a string
// options.display.hb_tpl =
// Some(std::fs::read_to_string(path).map_err(|e| Error::OpenFile(e, path.to_path_buf()))?);
// }
if let Some(path) = matches.get_one::<PathBuf>("tpl") {
// read handlebars file as a string
options.display.hb_tpl =
Some(std::fs::read_to_string(path).map_err(|e| Error::OpenFile(e, path.to_path_buf()))?);
}

//───────────────────────────────────────────────────────────────────────────────────
// manage misc. options
Expand Down Expand Up @@ -988,11 +1002,8 @@ fn init_term_logger(level: log::LevelFilter) -> crate::error::Result<()> {

#[cfg(test)]
mod tests {
use std::env::set_var;

use crate::dns::rfc::domain::ROOT;

use super::*;
use crate::dns::rfc::domain::ROOT;

#[test]
fn _split_args() {
Expand Down
40 changes: 36 additions & 4 deletions src/dns/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,17 @@ impl fmt::Display for Message {
}
}

impl Show for Message {
fn show(&self, display_options: &DisplayOptions, length: Option<usize>) {
// print out Query if requested
if display_options.show_question {
self.query.show(display_options, length);
}

self.response.show(display_options, length);
}
}

//───────────────────────────────────────────────────────────────────────────────────
// convenient struct for holding al messages
//───────────────────────────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -110,26 +121,47 @@ impl fmt::Display for MessageList {

impl ShowAll for MessageList {
fn show_all(&self, display_options: &DisplayOptions, info: QueryInfo) {
//───────────────────────────────────────────────────────────────────────────────────
// JSON
//───────────────────────────────────────────────────────────────────────────────────
if display_options.json_pretty {
let j = serde_json::json!({
"messages": self,
"info": info
});
println!("{}", serde_json::to_string_pretty(&j).unwrap());
return;
}

//───────────────────────────────────────────────────────────────────────────────────
// JSON pretty
} else if display_options.json {
//───────────────────────────────────────────────────────────────────────────────────
if display_options.json {
let j = serde_json::json!({
"messages": self,
"info": info
});
println!("{}", serde_json::to_string(&j).unwrap());
// Regular print out
} else {
return;
}

//───────────────────────────────────────────────────────────────────────────────────
// fancy print out when only one message
//───────────────────────────────────────────────────────────────────────────────────
if self.len() == 1 {
// we only have 1 message
let msg = &self[0];
let resp = msg.response();
resp.show(display_options, None);
}
//───────────────────────────────────────────────────────────────────────────────────
// when several messages, just print out the ANSWER
//───────────────────────────────────────────────────────────────────────────────────
else {
let max_length = self.max_length();

for msg in self.iter() {
msg.response().show(display_options, max_length);
msg.show(display_options, max_length);
}

if display_options.stats {
Expand Down
16 changes: 12 additions & 4 deletions src/dns/rfc/header.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fmt;

use colored::Colorize;
use type2network::{FromNetworkOrder, ToNetworkOrder};
use type2network_derive::{FromNetwork, ToNetwork};

Expand Down Expand Up @@ -40,6 +41,13 @@ pub struct Header {
// resource records in the additional records section.
}

impl Header {
// DoQ must set ID to 0: https://datatracker.ietf.org/doc/rfc9250/ section 4.2.1
pub fn set_id(&mut self, id: u16) {
self.id = id;
}
}

impl Default for Header {
fn default() -> Self {
// by default, we use the recursion desired flag at query
Expand All @@ -64,15 +72,15 @@ impl Default for Header {

impl fmt::Display for Header {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "id:0x{:X}({}) ", self.id, self.id)?;
write!(f, "flags:<{}> ", self.flags)?;
write!(f, "{}:0x{:X}({}) ", "id".bright_cyan(), self.id, self.id)?;
write!(f, "{}:<{}> ", "flags".bright_cyan(), self.flags)?;

if self.flags.qr == PacketType::Query {
write!(f, "QUERY:{}", self.qd_count)
write!(f, "{}:{}", "qd_count".bright_cyan(), self.qd_count)
} else {
write!(
f,
"QUERY:{}, ANSWER:{} AUTHORITY:{} ADDITIONAL:{}",
"qd_count:{}, an_count:{} ns_count:{} ar_count:{}",
self.qd_count, self.an_count, self.ns_count, self.ar_count
)
}
Expand Down
3 changes: 1 addition & 2 deletions src/dns/rfc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ pub mod cert;
pub mod cname;
pub mod csync;
pub mod dhcid;
// pub mod dname;
pub mod dnskey;
pub mod ds;
pub mod eui48;
Expand Down Expand Up @@ -51,7 +50,7 @@ pub mod soa;
pub mod srv;
pub mod sshfp;
pub mod svcb;
pub mod tkey;
// pub mod tkey;
pub mod tlsa;
pub mod txt;
pub mod type_bitmaps;
Expand Down
70 changes: 42 additions & 28 deletions src/dns/rfc/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

use colored::Colorize;
use log::{debug, trace};
use serde::Serialize;
use tokio::io::AsyncWriteExt;
Expand All @@ -11,23 +12,35 @@ use type2network::ToNetworkOrder;
use type2network_derive::ToNetwork;

use crate::error::{Dns, Error, Result};
use crate::show::{header_section, DisplayOptions, Show};
use crate::transport::network::Messenger;

use super::{
domain::DomainName, flags::BitFlags, header::Header, qclass::QClass, qtype::QType, question::Question,
resource_record::OPT,
};

const DEFAULT_BUFSIZE: u16 = 4096;

#[derive(Debug, ToNetwork, Serialize)]
pub enum MetaRR {
OPT(OPT),
}

impl fmt::Display for MetaRR {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MetaRR::OPT(opt) => write!(f, "{}", opt),
//_ => unimplemented!("Meta RR other than OPT not implemented"),
}
}
}

impl Default for MetaRR {
fn default() -> Self {
// https://datatracker.ietf.org/doc/html/rfc6891#section-6.2.5
// RFC recommends 4096 bytes to start with
Self::OPT(OPT::new(4096, None))
Self::OPT(OPT::new(DEFAULT_BUFSIZE, None))
}
}

Expand Down Expand Up @@ -160,37 +173,38 @@ impl Query {

Ok(sent)
}

pub fn display(&self) {
// header first
println!("HEADER: {}\n", self.header);
println!("QUESTION: {}\n", self.question);
}
}

// impl fmt::Debug for Query {
// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// write!(
// f,
// "length:<{:?}> header:<{:?}> question:<{:?}>",
// self.length, self.header, self.question
// )?;

// if let Some(add) = &self.additional {
// for rr in add {
// write!(f, "{:?}", rr)?;
// }
// }

// Ok(())
// }
// }

impl fmt::Display for Query {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.header)?;
write!(f, "{}", self.question)?;
write!(f, "{:?}", self.additional)
write!(f, "{}\n", header_section("QUERY", None))?;
write!(
f,
"{}({}) {}({})",
"HEADER".bright_blue(),
self.header,
"QUESTION".bright_blue(),
self.question,
)?;

if let Some(add) = &self.additional {
let mut s = String::with_capacity(100);
for meta_rr in add {
s += &format!("{:?}", meta_rr);
}
write!(f, " {}:({})", "ADDITIONAL".bright_blue(), s)?;
}

Ok(())
}
}

impl Show for Query {
fn show(&self, display_options: &DisplayOptions, _length: Option<usize>) {
// print out Query if requested
if display_options.show_question {
println!("{}", self);
}
}
}

Expand Down
Loading

0 comments on commit 030e23b

Please sign in to comment.