Skip to content

Commit

Permalink
Merge branch 'initial-nsec3-generation' into multiple-key-signing
Browse files Browse the repository at this point in the history
  • Loading branch information
ximon18 committed Nov 8, 2024
2 parents 06a9f0d + e1c1db8 commit 0a79594
Show file tree
Hide file tree
Showing 18 changed files with 1,022 additions and 40 deletions.
52 changes: 51 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ jobs:
run: cargo fmt --all -- --check
- run: cargo check --no-default-features --all-targets
- run: cargo test --all-features

minimal-versions:
name: Check minimal versions
runs-on: ubuntu-latest
Expand All @@ -60,4 +61,53 @@ jobs:
run: |
cargo +nightly update -Z minimal-versions
cargo check --all-features --all-targets --locked
# Note: This deliberately doesn't try to run the examples as some of them
# don't terminate and/or attempt to make network connections that will fail
# or perhaps be a nuisance to real name servers if run regularly by CI.
#
# Note: This is just a band aid, ideally there would be a way for Cargo to
# build/run examples using the feature set specified in Cargo.toml itself,
# but that isn't currently possible (see [1]).
#
# [1]: https://github.com/rust-lang/cargo/issues/4663)
build-examples:
name: Build examples
runs-on: ubuntu-latest
strategy:
matrix:
rust: [1.78.0, stable, beta, nightly]
steps:
- name: Checkout repository
uses: actions/checkout@v1
- name: Install Rust
uses: hecrj/setup-rust-action@v2
with:
rust-version: ${{ matrix.rust }}
- name: Compile all examples
shell: bash
# TODO: Emit matrix elements based on inspecting Cargo.toml so that
# each example runs as its own GitHub Actions step/job?
run: |
# Generate the set of cargo check --example X --features Y commands to
# run and store them in a temporary script. This command works by
# extracting the example blocks from the Cargo.toml file and the set
# of features that the block indicates are needed to run the example.
# E.g. given this block in Cargo.toml:
#
# [[example]]
# name = "lookup"
# required-features = ["resolv"]
#
# It outputs a line that looks like this:
#
# cargo check --example lookup --features resolv
#
# One line per example is output and the set of lines directed to a temporary
# shell script file which is then run in the next step.
cargo metadata --no-deps --format-version 1 | jq -r '.packages[0].targets[] | select(.kind[] | contains("example")) | "cargo check --example \(.name) --features \(."required-features" | flatten | join(","))"' > ${{ runner.temp }}/check-examples.sh
# Run the temporary script:
bash ${{ runner.temp }}/check-examples.sh
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ name = "domain"
path = "src/lib.rs"

[dependencies]
arbitrary = { version = "1.4.1", optional = true, features = ["derive"] }
octseq = { version = "0.5.2", default-features = false }
time = { version = "0.3.1", default-features = false }
rand = { version = "0.8", optional = true }
Expand Down
9 changes: 7 additions & 2 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ New
rather than a tree. ([#396])
* Changed `fmt::Display` for `HINFO` records to a show a quoted string.
([#421])
* Added support for `NAPTR` record type. ([#427] by [@weilence])

Bug fixes

* NSEC records should include themselves in the generated bitmap. ([#417])

Unstable features

* `unstable-server-transport`
Expand All @@ -31,8 +34,10 @@ Other changes

[#353]: https://github.com/NLnetLabs/domain/pull/353
[#396]: https://github.com/NLnetLabs/domain/pull/396
[#421]: https://github.com/NLnetLabs/domain/pull/412

[#417]: https://github.com/NLnetLabs/domain/pull/417
[#421]: https://github.com/NLnetLabs/domain/pull/421
[#427]: https://github.com/NLnetLabs/domain/pull/427
[@weilence]: https://github.com/weilence

## 0.10.3

Expand Down
174 changes: 174 additions & 0 deletions src/base/dig_printer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
use core::fmt;

use crate::rdata::AllRecordData;

use super::zonefile_fmt::ZonefileFmt;
use super::ParsedRecord;
use super::{opt::AllOptData, Message, Rtype};

/// Interal type for printing a message in dig style
///
/// This is only exposed to users of this library as `impl fmt::Display`.
pub(super) struct DigPrinter<'a, Octs> {
pub msg: &'a Message<Octs>,
}

impl<'a, Octs: AsRef<[u8]>> fmt::Display for DigPrinter<'a, Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let msg = self.msg.for_slice_ref();

// Header
let header = msg.header();
let counts = msg.header_counts();

writeln!(
f,
";; ->>HEADER<<- opcode: {}, rcode: {}, id: {}",
header.opcode().display_zonefile(false),
header.rcode(),
header.id()
)?;
write!(f, ";; flags: {}", header.flags())?;
writeln!(
f,
"; QUERY: {}, ANSWER: {}, AUTHORITY: {}, ADDITIONAL: {}",
counts.qdcount(),
counts.ancount(),
counts.nscount(),
counts.arcount()
)?;

// We need this later
let opt = msg.opt();

if let Some(opt) = opt.as_ref() {
writeln!(f, "\n;; OPT PSEUDOSECTION:")?;
writeln!(
f,
"; EDNS: version {}; flags: {}; udp: {}",
opt.version(),
opt.dnssec_ok(),
opt.udp_payload_size()
)?;
for option in opt.opt().iter::<AllOptData<_, _>>() {
use AllOptData::*;

match option {
Ok(opt) => match opt {
Nsid(nsid) => writeln!(f, "; NSID: {}", nsid)?,
Dau(dau) => writeln!(f, "; DAU: {}", dau)?,
Dhu(dhu) => writeln!(f, "; DHU: {}", dhu)?,
N3u(n3u) => writeln!(f, "; N3U: {}", n3u)?,
Expire(expire) => {
writeln!(f, "; EXPIRE: {}", expire)?
}
TcpKeepalive(opt) => {
writeln!(f, "; TCPKEEPALIVE: {}", opt)?
}
Padding(padding) => {
writeln!(f, "; PADDING: {}", padding)?
}
ClientSubnet(opt) => {
writeln!(f, "; CLIENTSUBNET: {}", opt)?
}
Cookie(cookie) => {
writeln!(f, "; COOKIE: {}", cookie)?
}
Chain(chain) => writeln!(f, "; CHAIN: {}", chain)?,
KeyTag(keytag) => {
writeln!(f, "; KEYTAG: {}", keytag)?
}
ExtendedError(extendederror) => {
writeln!(f, "; EDE: {}", extendederror)?
}
Other(other) => {
writeln!(f, "; {}", other.code())?;
}
},
Err(err) => {
writeln!(f, "; ERROR: bad option: {}.", err)?;
}
}
}
}

// Question
let questions = msg.question();
if counts.qdcount() > 0 {
writeln!(f, ";; QUESTION SECTION:")?;
for item in questions {
if let Ok(item) = item {
writeln!(f, "; {}", item)?;
} else {
writeln!(f, "; <invalid message>")?;
return Ok(());
};
}
}

// Answer
let section = questions.answer().unwrap();
if counts.ancount() > 0 {
writeln!(f, "\n;; ANSWER SECTION:")?;
for item in section {
if let Ok(item) = item {
write_record_item(f, &item)?;
} else {
writeln!(f, "; <invalid message>")?;
return Ok(());
};
}
}

// Authority
let section = section.next_section().unwrap().unwrap();
if counts.nscount() > 0 {
writeln!(f, "\n;; AUTHORITY SECTION:")?;
for item in section {
if let Ok(item) = item {
write_record_item(f, &item)?;
} else {
writeln!(f, "; <invalid message>")?;
return Ok(());
};
}
}

// Additional
let section = section.next_section().unwrap().unwrap();
if counts.arcount() > 1 || (opt.is_none() && counts.arcount() > 0) {
writeln!(f, "\n;; ADDITIONAL SECTION:")?;
for item in section {
if let Ok(item) = item {
if item.rtype() != Rtype::OPT {
write_record_item(f, &item)?;
}
} else {
writeln!(f, "; <invalid message>")?;
return Ok(());
};
}
}

Ok(())
}
}

fn write_record_item(
f: &mut impl fmt::Write,
item: &ParsedRecord<&[u8]>,
) -> Result<(), fmt::Error> {
let parsed = item.to_any_record::<AllRecordData<_, _>>();

match parsed {
Ok(item) => writeln!(f, "{}", item.display_zonefile(false)),
Err(_) => writeln!(
f,
"; {} {} {} {} <invalid data>",
item.owner(),
item.ttl().as_secs(),
item.class(),
item.rtype()
),
}
}
1 change: 1 addition & 0 deletions src/base/iana/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ macro_rules! int_enum {
$value:expr, $mnemonic:expr) )* ) => {
$(#[$attr])*
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct $ianatype($inttype);

impl $ianatype {
Expand Down
15 changes: 15 additions & 0 deletions src/base/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//!
//! [`Message`]: struct.Message.html

use super::dig_printer::DigPrinter;
use super::header::{Header, HeaderCounts, HeaderSection};
use super::iana::{Class, OptRcode, Rcode, Rtype};
use super::message_builder::{AdditionalBuilder, AnswerBuilder, PushError};
Expand Down Expand Up @@ -665,6 +666,20 @@ impl<Octs: Octets + ?Sized> Message<Octs> {
}
}

/// # Printing
impl<Octs: AsRef<[u8]>> Message<Octs> {
/// Create a wrapper that displays the message in a dig style
///
/// The dig style resembles a zonefile format (see also [`ZonefileFmt`]),
/// with additional lines that are commented out that contain information
/// about the header, OPT record and more.
///
/// [`ZonefileFmt`]: super::zonefile_fmt::ZonefileFmt
pub fn display_dig_style(&self) -> impl core::fmt::Display + '_ {
DigPrinter { msg: self }
}
}

//--- AsRef

// Octs here can’t be ?Sized or it’ll conflict with AsRef<[u8]> below.
Expand Down
1 change: 1 addition & 0 deletions src/base/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ pub use self::serial::Serial;

pub mod charstr;
pub mod cmp;
mod dig_printer;
pub mod header;
pub mod iana;
pub mod message;
Expand Down
1 change: 1 addition & 0 deletions src/base/name/absolute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ use std::vec::Vec;
/// [`Display`]: std::fmt::Display
#[derive(Clone)]
#[repr(transparent)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Name<Octs: ?Sized>(Octs);

impl Name<()> {
Expand Down
Loading

0 comments on commit 0a79594

Please sign in to comment.