pub mod dns;
pub mod port;
pub mod ssl;
pub mod types;
pub mod upstream;
pub use types::{
CheckSeverity, DnsCheckResult, HealthCheckResult, HealthStatus, NetworkCheckOptions,
PortCheckResult, SslCheckResult,
};
#[cfg(feature = "network")]
pub use dns::resolve_hostname;
#[cfg(feature = "network")]
pub use dns::resolve_hostnames;
#[cfg(feature = "network")]
pub use port::check_port;
#[cfg(feature = "network")]
pub use ssl::check_ssl_certificate;
#[cfg(feature = "network")]
pub use upstream::check_upstream_backend;
#[cfg(feature = "network")]
pub use upstream::check_upstream_http;
#[cfg(feature = "network")]
pub use upstream::UpstreamBackend;
pub use crate::network::dns::reverse_dns_lookup;
pub use crate::network::dns::validate_dns_config;
pub use crate::network::ssl::check_ssl_url;
use crate::{ast::Config, Result};
#[derive(Debug, Clone)]
pub struct NetworkCheckResult {
pub check_type: String,
pub target: String,
pub status: HealthStatus,
pub message: String,
pub severity: CheckSeverity,
pub details: Option<String>,
}
pub async fn check_all(
config: &Config,
options: NetworkCheckOptions,
) -> Result<Vec<NetworkCheckResult>> {
let mut results = Vec::new();
if options.check_ports {
results.extend(check_all_ports(config).await?);
}
if options.check_dns {
results.extend(check_all_dns(config).await?);
}
if options.check_upstreams {
results.extend(check_all_upstreams(config).await?);
}
if options.check_ssl {
results.extend(check_all_ssl(config).await?);
}
Ok(results)
}
#[allow(clippy::unused_async)]
async fn check_all_upstreams(_config: &Config) -> Result<Vec<NetworkCheckResult>> {
Ok(Vec::new())
}
#[allow(clippy::unused_async)]
async fn check_all_ssl(_config: &Config) -> Result<Vec<NetworkCheckResult>> {
Ok(Vec::new())
}
async fn check_all_ports(config: &Config) -> Result<Vec<NetworkCheckResult>> {
#[cfg(not(feature = "network"))]
{
let _ = config;
Ok(Vec::new())
}
#[cfg(feature = "network")]
{
use crate::extract::servers;
let mut results = Vec::new();
let servers = servers(config)?;
for server in servers {
for listen in &server.listen {
match check_port(&listen.address, listen.port).await {
Ok(check) => results.push(NetworkCheckResult {
check_type: "port".to_string(),
target: format!("{}:{}", listen.address, listen.port),
status: check.status,
message: check.message,
severity: check.severity,
details: check.details,
}),
Err(e) => results.push(NetworkCheckResult {
check_type: "port".to_string(),
target: format!("{}:{}", listen.address, listen.port),
status: HealthStatus::Error,
message: format!("Port check failed: {e}"),
severity: CheckSeverity::Error,
details: None,
}),
}
}
}
Ok(results)
}
}
async fn check_all_dns(config: &Config) -> Result<Vec<NetworkCheckResult>> {
#[cfg(not(feature = "network"))]
{
let _ = config;
Ok(Vec::new())
}
#[cfg(feature = "network")]
{
use crate::extract::servers;
let mut results = Vec::new();
let servers = servers(config)?;
for server in servers {
for name in &server.server_names {
if name == "_" || name == "localhost" || name.contains('*') {
continue;
}
match resolve_hostname(name).await {
Ok(check) => results.push(NetworkCheckResult {
check_type: "dns".to_string(),
target: name.clone(),
status: check.status,
message: check.message,
severity: check.severity,
details: check.details,
}),
Err(e) => results.push(NetworkCheckResult {
check_type: "dns".to_string(),
target: name.clone(),
status: HealthStatus::Error,
message: format!("DNS resolution failed: {e}"),
severity: CheckSeverity::Warning,
details: None,
}),
}
}
}
Ok(results)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_network_check_options_default() {
let options = NetworkCheckOptions::default();
assert!(options.check_ports);
assert!(options.check_dns);
assert!(options.check_ssl);
assert!(options.check_upstreams);
}
#[test]
fn test_network_check_result_creation() {
let result = NetworkCheckResult {
check_type: "test".to_string(),
target: "localhost:80".to_string(),
status: HealthStatus::Healthy,
message: "OK".to_string(),
severity: CheckSeverity::Info,
details: None,
};
assert_eq!(result.check_type, "test");
assert_eq!(result.status, HealthStatus::Healthy);
}
}