Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
ae87d0b
Upstream TSIG support.
ximon18 Apr 2, 2026
25fdfe9
Fix RustDoc violations.
ximon18 Apr 2, 2026
8a11e9d
(De)serialize to Base64.
ximon18 Apr 3, 2026
52c88cf
cargo fmt.
ximon18 Apr 3, 2026
79b3308
(de)serialize TSIG algorithm names exactly as defined in the IANA reg…
ximon18 Apr 7, 2026
4b07b11
Use ^ instead of ! and start adding man page content.
ximon18 Apr 7, 2026
4d56ffb
Add a cascade tsig man page.
ximon18 Apr 7, 2026
53f6205
More TSIG related man page updates.
ximon18 Apr 7, 2026
9b50f3c
Try adding an NSD integration page to showcase TSIG support.
ximon18 Apr 7, 2026
5845baf
Expand the NSD example.
ximon18 Apr 7, 2026
7002eb3
Tweak the NSD example.
ximon18 Apr 8, 2026
0750e4e
Advise how to create a TSIG key.
ximon18 Apr 8, 2026
7143a54
Start creating a system test for upstream TSIG.
ximon18 Apr 8, 2026
c0724ee
FIX: allow hmac- when specifying the algorithm name to `tsig key add`.
ximon18 Apr 8, 2026
678d55e
FIX: Wrong `tsig add` subcommand documentation.
ximon18 Apr 8, 2026
0c0d38c
Make the upstream TSIG system test try using TSIG.
ximon18 Apr 8, 2026
432e779
Merge branch 'main' into tsig-upstream-support
ximon18 Apr 10, 2026
75b6ee3
Merge branch 'main' into tsig-upstream-support
ximon18 Apr 10, 2026
b44b805
Fix merge error.
ximon18 Apr 10, 2026
059cd0a
Fix sphinx-build WARNING: Title underline too short.
ximon18 Apr 10, 2026
5c38ef9
Add `tsig list` CLI subcommand.
ximon18 Apr 10, 2026
80b6b3d
Document the tsig list subcommand.
ximon18 Apr 10, 2026
5c5ef7e
Commit updated generated man pages.
ximon18 Apr 10, 2026
1908500
Remove accidentally commited sphinx-build outputs.
ximon18 Apr 10, 2026
0426bc6
Remove accidentally commited sphinx-build outputs.
ximon18 Apr 10, 2026
15d6da2
Add TODO notes.
ximon18 Apr 10, 2026
86010bb
Introduce public-nameservers and send it to keyset. Handle TSIG related
Philip-NLnetLabs Apr 13, 2026
a83425a
Merge branch 'tsig-upstream-support' into keyset-upstream-nameserver
Philip-NLnetLabs Apr 13, 2026
18f464f
Something went wrong during the merge. First fix.
Philip-NLnetLabs Apr 13, 2026
63256bd
Fix call to reloa_all.
Philip-NLnetLabs Apr 13, 2026
542d70e
Implement `cascade tsig remove`.
ximon18 Apr 13, 2026
e03487b
Merge branch 'main' into tsig-upstream-support
ximon18 Apr 14, 2026
e79a1ad
WIP
ximon18 Apr 14, 2026
596bbb9
WIP
ximon18 Apr 14, 2026
575c152
Bump dnst for set publication-server and set tsig-store-path support.
ximon18 Apr 15, 2026
ce919eb
WIP
ximon18 Apr 15, 2026
8193f94
Merge branch 'tsig-upstream-support' into keyset-upstream-nameserver
ximon18 Apr 15, 2026
1fb2e48
Merge branch 'keyset-upstream-nameserver' into tsig-downstream-support
ximon18 Apr 15, 2026
67becab
Introduce public-nameservers and send it to keyset. Handle TSIG relat…
Philip-NLnetLabs Apr 15, 2026
b8729fb
Merge branch 'tsig-upstream-support' of github.com:NLnetLabs/cascade …
ximon18 Apr 15, 2026
271bfac
Merge branch 'main' into tsig-upstream-support
ximon18 Apr 15, 2026
e6a5192
Fix failing upstream-tsig system test by bumping the dnst version use…
ximon18 Apr 15, 2026
30ee572
Merge branch 'tsig-upstream-support' into tsig-downstream-support
ximon18 Apr 15, 2026
11bf96a
Improve the policy template documentation for send-notify-to.
ximon18 Apr 15, 2026
787c1b8
Add more RustDoc on the NameserverCommsPolicy type.
ximon18 Apr 15, 2026
91462ac
FIX: Restore zone TSIG key state on startup.
ximon18 Apr 16, 2026
3331ff9
Add some more comments to the code.
ximon18 Apr 16, 2026
ee907f2
Merge branch 'main' into tsig-upstream-support
ximon18 Apr 17, 2026
3a3ce07
Merge branch 'tsig-upstream-support' into tsig-downstream-support
ximon18 Apr 17, 2026
f428888
Merge branch 'tsig-downstream-support' into restore-tsig-keys-in-zone…
ximon18 Apr 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ assets = [
["doc/manual/build/man/cascade-config.1", "usr/share/man/man1/cascade-config.1", "644"],
["doc/manual/build/man/cascade-health.1", "usr/share/man/man1/cascade-health.1", "644"],
["doc/manual/build/man/cascade-hsm.1", "usr/share/man/man1/cascade-hsm.1", "644"],
["doc/manual/build/man/cascade-tsig.1", "usr/share/man/man1/cascade-tsig.1", "644"],
["doc/manual/build/man/cascade-keyset.1", "usr/share/man/man1/cascade-keyset.1", "644"],
["doc/manual/build/man/cascade-policy.1", "usr/share/man/man1/cascade-policy.1", "644"],
["doc/manual/build/man/cascade-status.1", "usr/share/man/man1/cascade-status.1", "644"],
Expand Down Expand Up @@ -301,6 +302,7 @@ assets = [
{ source = "doc/manual/build/man/cascade-config.1", dest = "/usr/share/man/man1/cascade-config.1", mode = "644", doc = true },
{ source = "doc/manual/build/man/cascade-health.1", dest = "/usr/share/man/man1/cascade-health.1", mode = "644", doc = true },
{ source = "doc/manual/build/man/cascade-hsm.1", dest = "/usr/share/man/man1/cascade-hsm.1", mode = "644", doc = true },
{ source = "doc/manual/build/man/cascade-tsig.1", dest = "/usr/share/man/man1/cascade-tsig.1", mode = "644", doc = true },
{ source = "doc/manual/build/man/cascade-keyset.1", dest = "/usr/share/man/man1/cascade-keyset.1", mode = "644", doc = true },
{ source = "doc/manual/build/man/cascade-policy.1", dest = "/usr/share/man/man1/cascade-policy.1", mode = "644", doc = true },
{ source = "doc/manual/build/man/cascade-status.1", dest = "/usr/share/man/man1/cascade-status.1", mode = "644", doc = true },
Expand Down
2 changes: 1 addition & 1 deletion crates/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ features = ["serde1"]
[dependencies.domain]
workspace = true
# TODO: Enable and use 'new::base'?
features = ["bytes", "serde"]
features = ["bytes", "serde", "tsig"]

# The API uses 'serde' for transforming high-level types to and from the
# underlying wire format.
Expand Down
150 changes: 143 additions & 7 deletions crates/api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::collections::HashMap;
use std::fmt::{self, Display};
use std::net::{IpAddr, SocketAddr};
use std::time::{Duration, SystemTime};

use camino::{Utf8Path, Utf8PathBuf};
use domain::tsig::KeyName;
use serde::{Deserialize, Serialize};

pub use domain::base::Serial;
Expand Down Expand Up @@ -187,6 +189,94 @@ pub struct KmipKeyImport {
pub flags: String,
}

//----------- TsigKeyName -----------------------------------------------------

/// The name of a TSIG key.
pub type TsigKeyName = domain::tsig::KeyName;

//----------- TsigAdd ---------------------------------------------------------

/// Add a TSIG key to Cascade.
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct TsigAdd {
/// The name of the TSIG key to add.
pub name: TsigKeyName,

/// The algorithm of the TSIG key.
pub alg: TsigAlgorithm,

/// The base64 encoded key material bytes.
pub secret: String,
}

/// The successful result of adding a TSIG key to Cascade.
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct TsigAddResult;

/// An error result indicating why an attempt to add a TSIG key to Cascade
/// failed.
#[derive(Deserialize, Serialize, Debug, Clone)]
pub enum TsigAddError {
/// A TSIG key by the given name already exists in Cascade.
AlreadyExists,

/// The provided TSIG key secret was not correctly base64 encoded.
InvalidBase64Secret,
}

impl Display for TsigAddError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TsigAddError::AlreadyExists => write!(f, "TSIG key already exists"),
TsigAddError::InvalidBase64Secret => write!(f, "invalid TSIG base64 encoded secret"),
}
}
}

//------------ TsigRemove ----------------------------------------------------

/// The successful result of removing a TSIG key from Cascade.
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct TsigRemoveResult;

/// An error result indicating why an attempt to remove a TSIG key from
/// Cascade failed.
#[derive(Deserialize, Serialize, Debug, Clone)]
pub enum TsigRemoveError {
/// The specified TSIG key name was not found in Cascade.
NotFound,

/// The specified TSIG key cannot be removed as it is in use.
InUse,
}

impl fmt::Display for TsigRemoveError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
TsigRemoveError::NotFound => "no such TSIG key was found",
TsigRemoveError::InUse => "the TSIG key cannot be removed as it is in use",
})
}
}

//------------ TsigListResult ------------------------------------------------

/// The successful result of listing TSIG Cascade keys known to Cascade.
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct TsigListResult {
/// The set of TSIG keys known to Cascade plus information about each key.
pub tsig_keys: HashMap<TsigKeyName, TsigListResultItem>,
}

/// Information about a single listed TSIG key.
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct TsigListResultItem {
/// The set of zones with which this TSIG key is used.
pub zones: Vec<ZoneName>,
}

//----------- ZoneAdd --------------------------------------------------------

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ZoneAdd {
pub name: ZoneName,
Expand All @@ -206,6 +296,8 @@ pub enum ZoneAddError {
AlreadyExists,
NoSuchPolicy,
PolicyMidDeletion,
InvalidTsigKeyName(String),
NoSuchTsigKey,
Other(String),
}

Expand All @@ -215,6 +307,8 @@ impl fmt::Display for ZoneAddError {
Self::AlreadyExists => "a zone of this name already exists",
Self::NoSuchPolicy => "no policy with that name exists",
Self::PolicyMidDeletion => "the specified policy is being deleted",
Self::InvalidTsigKeyName(reason) => reason,
Self::NoSuchTsigKey => "no TSIG key with that name exists",
Self::Other(reason) => reason,
})
}
Expand Down Expand Up @@ -290,18 +384,30 @@ impl Display for ZoneSource {
}
}

/// Support parsing of ``-source`` command line arguments.
///
/// Supported forms:
/// - `<IP_ADDRESS>[:<PORT>][^<TSIG_KEY_NAME>]`
/// - `</PATH/TO/ZONE/FILE/TO/LOAD>`
impl From<&str> for ZoneSource {
fn from(s: &str) -> Self {
fn from(mut s: &str) -> Self {
// Split out any provided TSIG key from the rest of the
// source argument.
let tsig_key = s.split_once('^').map(|(new_s, k)| {
s = new_s;
k.to_string()
});

if let Ok(addr) = s.parse::<SocketAddr>() {
ZoneSource::Server {
addr,
tsig_key: None,
tsig_key,
xfr_status: Default::default(),
}
} else if let Ok(addr) = s.parse::<IpAddr>() {
ZoneSource::Server {
addr: SocketAddr::new(addr, DEFAULT_AXFR_PORT),
tsig_key: None,
tsig_key,
xfr_status: Default::default(),
}
} else {
Expand Down Expand Up @@ -501,6 +607,26 @@ impl Display for KeyType {
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum TsigAlgorithm {
Sha1,
Sha256,
Sha384,
Sha512,
}

impl Display for TsigAlgorithm {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TsigAlgorithm::Sha1 => "hmac-sha1",
TsigAlgorithm::Sha256 => "hmac-sha256",
TsigAlgorithm::Sha384 => "hmac-sha384",
TsigAlgorithm::Sha512 => "hmac-sha512",
}
.fmt(f)
}
}

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ZoneHistory {
pub history: Vec<HistoryItem>,
Expand Down Expand Up @@ -660,12 +786,15 @@ pub struct KeyMsg {
#[derive(Deserialize, Serialize, Debug, Clone)]
pub enum PolicyReloadError {
Io(Utf8PathBuf, String),
Check(String),
}

impl Display for PolicyReloadError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let PolicyReloadError::Io(p, e) = self;
format!("{p}: {e}").fmt(f)
match self {
PolicyReloadError::Io(p, e) => format!("{p}: {e}").fmt(f),
PolicyReloadError::Check(e) => e.to_string().fmt(f),
}
}
}

Expand Down Expand Up @@ -749,12 +878,19 @@ pub struct OutboundPolicyInfo {

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct NameserverCommsPolicyInfo {
pub addr: SocketAddr,
pub addr: Option<SocketAddr>,
pub tsig_key_name: Option<KeyName>,
}

impl std::fmt::Display for NameserverCommsPolicyInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.addr)
if let Some(addr) = self.addr {
write!(f, "{addr}")?;
}
if let Some(tsig_key_name) = &self.tsig_key_name {
write!(f, "^{tsig_key_name}")?;
}
Ok(())
}
}

Expand Down
10 changes: 6 additions & 4 deletions crates/cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod keyset;
pub mod policy;
pub mod status;
pub mod template;
pub mod tsig;
pub mod zone;

use crate::client::CascadeApiClient;
Expand Down Expand Up @@ -37,10 +38,10 @@ pub enum Command {
/// Execute manual key roll or key removal commands
#[command(name = "keyset")]
KeySet(self::keyset::KeySet),
//
// /// Manage keys
// #[command(name = "key")]
// Key(self::key::Key),

/// Manage TSIG keys
#[command(name = "tsig")]
Tsig(self::tsig::Tsig),
// - Command: add/remove/modify a zone
// - Command: add/remove/modify a key for a zone
// - Command: add/remove/modify a key
Expand Down Expand Up @@ -74,6 +75,7 @@ impl Command {
Self::Policy(policy) => policy.execute(client).await,
Self::KeySet(keyset) => keyset.execute(client).await,
Self::Hsm(hsm) => hsm.execute(client).await,
Self::Tsig(tsig) => tsig.execute(client).await,
Self::Template(template) => template.execute(client).await,
}
}
Expand Down
Loading
Loading