use super::rndc::*;
#[test]
fn test_rndc_rejects_weak_hmac_algorithms() {
for weak in ["md5", "sha1", "hmac-md5", "hmac-sha1"] {
let result = RndcExecutor::new(
"127.0.0.1:953".to_string(),
weak.to_string(),
"dGVzdC1zZWNyZXQ=".to_string(),
);
assert!(result.is_err(), "weak algorithm {weak} should be rejected");
}
}
#[test]
fn test_rndc_accepts_sha2_algorithms() {
for ok in ["sha256", "hmac-sha256", "sha384", "sha512"] {
let result = RndcExecutor::new(
"127.0.0.1:953".to_string(),
ok.to_string(),
"dGVzdC1zZWNyZXQ=".to_string(),
);
assert!(result.is_ok(), "algorithm {ok} should be accepted");
}
}
#[test]
fn test_validate_rndc_zone_name_rejects_injection() {
for bad in [
"",
"../etc/passwd",
"zone name",
"zone;reload",
"zone\nreload",
"a..b",
] {
assert!(
validate_rndc_zone_name(bad).is_err(),
"expected {bad:?} to be rejected"
);
}
assert!(validate_rndc_zone_name("example.com").is_ok());
assert!(validate_rndc_zone_name("_dmarc.example.com").is_ok());
}
#[test]
fn test_rndc_config_debug_redacts_secret() {
let cfg = RndcConfig {
server: "127.0.0.1:953".to_string(),
algorithm: "sha256".to_string(),
secret: "SUPERSECRETBASE64VALUE==".to_string(),
};
let debug = format!("{:?}", cfg);
assert!(
!debug.contains("SUPERSECRETBASE64VALUE"),
"TSIG secret leaked via Debug: {debug}"
);
assert!(debug.contains("[REDACTED]"), "expected redaction: {debug}");
}
#[test]
fn test_rndc_executor_creation() {
let result = RndcExecutor::new(
"127.0.0.1:953".to_string(),
"sha256".to_string(),
"dGVzdC1zZWNyZXQtaGVyZQ==".to_string(), );
assert!(result.is_ok());
}
#[test]
fn test_rndc_executor_creation_with_hmac_prefix() {
let result = RndcExecutor::new(
"127.0.0.1:953".to_string(),
"hmac-sha256".to_string(),
"dGVzdC1zZWNyZXQtaGVyZQ==".to_string(),
);
assert!(result.is_ok());
}
#[test]
fn test_rndc_executor_creation_with_all_algorithms() {
let algorithms = vec!["sha224", "sha256", "sha384", "sha512"];
for algo in algorithms {
let result = RndcExecutor::new(
"127.0.0.1:953".to_string(),
algo.to_string(),
"dGVzdC1zZWNyZXQtaGVyZQ==".to_string(),
);
assert!(result.is_ok(), "Algorithm {} should be valid", algo);
}
}
#[test]
fn test_rndc_executor_creation_with_hmac_prefix_all_algorithms() {
let algorithms = vec!["hmac-sha224", "hmac-sha256", "hmac-sha384", "hmac-sha512"];
for algo in algorithms {
let result = RndcExecutor::new(
"127.0.0.1:953".to_string(),
algo.to_string(),
"dGVzdC1zZWNyZXQtaGVyZQ==".to_string(),
);
assert!(result.is_ok(), "Algorithm {} should be valid", algo);
}
}
#[test]
fn test_rndc_executor_creation_with_invalid_algorithm() {
let result = RndcExecutor::new(
"127.0.0.1:953".to_string(),
"invalid-algo".to_string(),
"dGVzdC1zZWNyZXQtaGVyZQ==".to_string(),
);
assert!(result.is_err());
let error_msg = result.err().unwrap().to_string();
assert!(error_msg.contains("Invalid or deprecated algorithm"));
}
#[test]
fn test_rndc_executor_creation_with_whitespace() {
let result = RndcExecutor::new(
" 127.0.0.1:953 ".to_string(),
" sha256 ".to_string(),
" dGVzdC1zZWNyZXQtaGVyZQ== ".to_string(),
);
assert!(result.is_ok());
}
#[test]
fn test_rndc_executor_clone() {
let executor = RndcExecutor::new(
"127.0.0.1:953".to_string(),
"sha256".to_string(),
"dGVzdC1zZWNyZXQtaGVyZQ==".to_string(),
)
.expect("Failed to create executor");
let cloned = executor.clone();
drop(cloned);
}
#[test]
fn test_rndc_config() {
let config = RndcConfig {
server: "127.0.0.1:953".to_string(),
algorithm: "sha256".to_string(),
secret: "dGVzdC1zZWNyZXQ=".to_string(),
};
assert_eq!(config.server, "127.0.0.1:953");
assert_eq!(config.algorithm, "sha256");
assert_eq!(config.secret, "dGVzdC1zZWNyZXQ=");
}
#[test]
fn test_rndc_config_clone() {
let config = RndcConfig {
server: "127.0.0.1:953".to_string(),
algorithm: "sha256".to_string(),
secret: "dGVzdC1zZWNyZXQ=".to_string(),
};
let cloned = config.clone();
assert_eq!(config.server, cloned.server);
assert_eq!(config.algorithm, cloned.algorithm);
assert_eq!(config.secret, cloned.secret);
}
#[test]
fn test_parse_rndc_conf_with_temp_file() {
use std::io::Write;
use tempfile::NamedTempFile;
let mut temp_file = NamedTempFile::new().unwrap();
writeln!(
temp_file,
r#"
key "rndc-key" {{
algorithm hmac-sha256;
secret "dGVzdC1zZWNyZXQtaGVyZQ==";
}};
options {{
default-server 127.0.0.1;
default-key "rndc-key";
default-port 953;
}};
"#
)
.unwrap();
let result = parse_rndc_conf(temp_file.path().to_str().unwrap());
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.server, "127.0.0.1:953");
assert_eq!(config.algorithm, "hmac-sha256");
assert_eq!(config.secret, "dGVzdC1zZWNyZXQtaGVyZQ==");
}
#[test]
fn test_parse_rndc_conf_with_default_port() {
use std::io::Write;
use tempfile::NamedTempFile;
let mut temp_file = NamedTempFile::new().unwrap();
writeln!(
temp_file,
r#"
key "test-key" {{
algorithm sha256;
secret "dGVzdC1zZWNyZXQ=";
}};
options {{
default-server localhost;
}};
"#
)
.unwrap();
let result = parse_rndc_conf(temp_file.path().to_str().unwrap());
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.server, "localhost:953"); }
#[test]
fn test_parse_rndc_conf_with_server_and_port() {
use std::io::Write;
use tempfile::NamedTempFile;
let mut temp_file = NamedTempFile::new().unwrap();
writeln!(
temp_file,
r#"
key "test-key" {{
algorithm sha256;
secret "dGVzdC1zZWNyZXQ=";
}};
options {{
default-server 192.168.1.1:8953;
}};
"#
)
.unwrap();
let result = parse_rndc_conf(temp_file.path().to_str().unwrap());
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.server, "192.168.1.1:8953"); }
#[test]
fn test_parse_rndc_conf_with_no_default_server() {
use std::io::Write;
use tempfile::NamedTempFile;
let mut temp_file = NamedTempFile::new().unwrap();
writeln!(
temp_file,
r#"
key "test-key" {{
algorithm sha256;
secret "dGVzdC1zZWNyZXQ=";
}};
"#
)
.unwrap();
let result = parse_rndc_conf(temp_file.path().to_str().unwrap());
assert!(result.is_ok());
let config = result.unwrap();
assert_eq!(config.server, "127.0.0.1:953"); }
#[test]
fn test_parse_rndc_conf_with_no_keys() {
use std::io::Write;
use tempfile::NamedTempFile;
let mut temp_file = NamedTempFile::new().unwrap();
writeln!(
temp_file,
r#"
options {{
default-server 127.0.0.1;
}};
"#
)
.unwrap();
let result = parse_rndc_conf(temp_file.path().to_str().unwrap());
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("No keys found"));
}
#[test]
fn test_parse_rndc_conf_with_missing_default_key() {
use std::io::Write;
use tempfile::NamedTempFile;
let mut temp_file = NamedTempFile::new().unwrap();
writeln!(
temp_file,
r#"
key "test-key" {{
algorithm sha256;
secret "dGVzdC1zZWNyZXQ=";
}};
options {{
default-key "non-existent-key";
}};
"#
)
.unwrap();
let result = parse_rndc_conf(temp_file.path().to_str().unwrap());
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("not found"));
}
#[test]
fn test_parse_rndc_conf_file_not_found() {
let result = parse_rndc_conf("/nonexistent/path/rndc.conf");
assert!(result.is_err());
}