Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,13 @@ mod metrics_test;
#[cfg(test)]
mod middleware_test;
#[cfg(test)]
mod rate_limit_test;
#[cfg(test)]
mod rndc_test;
#[cfg(test)]
mod rndc_parser_tests;

#[cfg(test)]
mod rndc_types_tests;

#[cfg(test)]
mod types_test;
#[cfg(test)]
Expand Down
94 changes: 53 additions & 41 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,50 +222,62 @@ async fn main() -> anyhow::Result<()> {
}

// get rndc configuration from environment or fallback to rndc.conf
let (rndc_server, rndc_algorithm, rndc_secret) = if let Ok(secret) =
std::env::var("RNDC_SECRET")
{
// environment variables provided
let server = std::env::var("RNDC_SERVER").unwrap_or_else(|_| "127.0.0.1:953".to_string());
let algorithm = std::env::var("RNDC_ALGORITHM").unwrap_or_else(|_| "sha256".to_string());
info!("using rndc configuration from environment variables");
info!("rndc server: {}", server);
info!("rndc algorithm: {}", algorithm);
(server, algorithm, secret)
} else {
// try to parse from rndc.conf files
info!("RNDC_SECRET not set, attempting to parse rndc.conf");

let config_paths = vec!["/etc/bind/rndc.conf", "/etc/rndc.conf"];
let mut config = None;

for path in &config_paths {
match bindcar::rndc::parse_rndc_conf(path) {
Ok(cfg) => {
info!("successfully parsed rndc configuration from {}", path);
config = Some(cfg);
break;
}
Err(e) => {
debug!("failed to parse {}: {}", path, e);
}
}
}

match config {
Some(cfg) => {
info!("rndc server: {}", cfg.server);
info!("rndc algorithm: {}", cfg.algorithm);
(cfg.server, cfg.algorithm, cfg.secret)
// Each parameter is checked independently - env var takes priority, then rndc.conf

// Try to parse rndc.conf file first to have fallback values
let config_paths = vec!["/etc/bind/rndc.conf", "/etc/rndc.conf"];
let mut parsed_config = None;

for path in &config_paths {
match bindcar::rndc::parse_rndc_conf(path) {
Ok(cfg) => {
info!("successfully parsed rndc configuration from {}", path);
parsed_config = Some(cfg);
break;
}
None => {
error!("rndc configuration not found!");
error!("either set RNDC_SECRET environment variable or ensure /etc/bind/rndc.conf exists");
return Err(anyhow::anyhow!(
"rndc configuration required: set RNDC_SECRET env var or create /etc/bind/rndc.conf"
));
Err(e) => {
debug!("failed to parse {}: {}", path, e);
}
}
}

// Check each parameter independently: env var first, then rndc.conf, then hardcoded default
let rndc_server = if let Ok(server) = std::env::var("RNDC_SERVER") {
info!("using RNDC_SERVER from environment: {}", server);
server
} else if let Some(ref cfg) = parsed_config {
info!("using server from rndc.conf: {}", cfg.server);
cfg.server.clone()
} else {
let default = "127.0.0.1:953".to_string();
warn!("using default RNDC_SERVER: {}", default);
default
};

let rndc_algorithm = if let Ok(algorithm) = std::env::var("RNDC_ALGORITHM") {
info!("using RNDC_ALGORITHM from environment: {}", algorithm);
algorithm
} else if let Some(ref cfg) = parsed_config {
info!("using algorithm from rndc.conf: {}", cfg.algorithm);
cfg.algorithm.clone()
} else {
let default = "sha256".to_string();
warn!("using default RNDC_ALGORITHM: {}", default);
default
};

let rndc_secret = if let Ok(secret) = std::env::var("RNDC_SECRET") {
info!("using RNDC_SECRET from environment");
secret
} else if let Some(ref cfg) = parsed_config {
info!("using secret from rndc.conf");
cfg.secret.clone()
} else {
error!("rndc configuration not found!");
error!("either set RNDC_SECRET environment variable or ensure /etc/bind/rndc.conf exists");
return Err(anyhow::anyhow!(
"rndc configuration required: set RNDC_SECRET env var or create /etc/bind/rndc.conf"
));
};

// verify zone directory exists
Expand Down
53 changes: 0 additions & 53 deletions src/rate_limit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,56 +87,3 @@ impl RateLimitConfig {
Ok(())
}
}

#[cfg(test)]
mod rate_limit_test {
use super::*;

#[test]
fn test_rate_limit_config_default() {
let config = RateLimitConfig::default();
assert_eq!(config.requests_per_period, 100);
assert_eq!(config.period_secs, 60);
assert_eq!(config.burst_size, 10);
assert!(config.enabled);
}

#[test]
fn test_rate_limit_config_validation() {
let config = RateLimitConfig::default();
assert!(config.validate().is_ok());

let invalid_config = RateLimitConfig {
requests_per_period: 0,
..Default::default()
};
assert!(invalid_config.validate().is_err());

let invalid_config = RateLimitConfig {
period_secs: 0,
..Default::default()
};
assert!(invalid_config.validate().is_err());

let invalid_config = RateLimitConfig {
burst_size: 0,
..Default::default()
};
assert!(invalid_config.validate().is_err());
}

#[test]
fn test_rate_limit_config_from_env() {
// Test with no env vars set - should use defaults
std::env::remove_var("RATE_LIMIT_ENABLED");
std::env::remove_var("RATE_LIMIT_REQUESTS");
std::env::remove_var("RATE_LIMIT_PERIOD_SECS");
std::env::remove_var("RATE_LIMIT_BURST");

let config = RateLimitConfig::from_env();
assert_eq!(config.requests_per_period, 100);
assert_eq!(config.period_secs, 60);
assert_eq!(config.burst_size, 10);
assert!(config.enabled);
}
}
49 changes: 49 additions & 0 deletions src/rate_limit_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use crate::rate_limit::RateLimitConfig;

#[test]
fn test_rate_limit_config_default() {
let config = RateLimitConfig::default();
assert_eq!(config.requests_per_period, 100);
assert_eq!(config.period_secs, 60);
assert_eq!(config.burst_size, 10);
assert!(config.enabled);
}

#[test]
fn test_rate_limit_config_validation() {
let config = RateLimitConfig::default();
assert!(config.validate().is_ok());

let invalid_config = RateLimitConfig {
requests_per_period: 0,
..Default::default()
};
assert!(invalid_config.validate().is_err());

let invalid_config = RateLimitConfig {
period_secs: 0,
..Default::default()
};
assert!(invalid_config.validate().is_err());

let invalid_config = RateLimitConfig {
burst_size: 0,
..Default::default()
};
assert!(invalid_config.validate().is_err());
}

#[test]
fn test_rate_limit_config_from_env() {
// Test with no env vars set - should use defaults
std::env::remove_var("RATE_LIMIT_ENABLED");
std::env::remove_var("RATE_LIMIT_REQUESTS");
std::env::remove_var("RATE_LIMIT_PERIOD_SECS");
std::env::remove_var("RATE_LIMIT_BURST");

let config = RateLimitConfig::from_env();
assert_eq!(config.requests_per_period, 100);
assert_eq!(config.period_secs, 60);
assert_eq!(config.burst_size, 10);
assert!(config.enabled);
}
Loading