pub mod dnssec;
use std::fs::File;
use std::io::Read;
use std::net::{AddrParseError, Ipv4Addr, Ipv6Addr};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::time::Duration;
use cfg_if::cfg_if;
use serde::{self, Deserialize};
use toml;
use crate::proto::error::ProtoResult;
use crate::proto::rr::Name;
use crate::authority::ZoneType;
use crate::error::{ConfigError, ConfigResult};
use crate::store::StoreConfig;
static DEFAULT_PATH: &str = "/var/named"; static DEFAULT_PORT: u16 = 53;
static DEFAULT_TLS_PORT: u16 = 853;
static DEFAULT_HTTPS_PORT: u16 = 443;
static DEFAULT_QUIC_PORT: u16 = 853; static DEFAULT_TCP_REQUEST_TIMEOUT: u64 = 5;
#[derive(Deserialize, Debug)]
pub struct Config {
#[serde(default)]
listen_addrs_ipv4: Vec<String>,
#[serde(default)]
listen_addrs_ipv6: Vec<String>,
listen_port: Option<u16>,
tls_listen_port: Option<u16>,
https_listen_port: Option<u16>,
quic_listen_port: Option<u16>,
tcp_request_timeout: Option<u64>,
log_level: Option<String>,
directory: Option<String>,
#[serde(default)]
zones: Vec<ZoneConfig>,
#[cfg(feature = "dnssec")]
tls_cert: Option<dnssec::TlsCertConfig>,
}
impl Config {
pub fn read_config(path: &Path) -> ConfigResult<Self> {
let mut file: File = File::open(path)?;
let mut toml: String = String::new();
file.read_to_string(&mut toml)?;
toml.parse().map_err(Into::into)
}
pub fn get_listen_addrs_ipv4(&self) -> Result<Vec<Ipv4Addr>, AddrParseError> {
self.listen_addrs_ipv4.iter().map(|s| s.parse()).collect()
}
pub fn get_listen_addrs_ipv6(&self) -> Result<Vec<Ipv6Addr>, AddrParseError> {
self.listen_addrs_ipv6.iter().map(|s| s.parse()).collect()
}
pub fn get_listen_port(&self) -> u16 {
self.listen_port.unwrap_or(DEFAULT_PORT)
}
pub fn get_tls_listen_port(&self) -> u16 {
self.tls_listen_port.unwrap_or(DEFAULT_TLS_PORT)
}
pub fn get_https_listen_port(&self) -> u16 {
self.https_listen_port.unwrap_or(DEFAULT_HTTPS_PORT)
}
pub fn get_quic_listen_port(&self) -> u16 {
self.quic_listen_port.unwrap_or(DEFAULT_QUIC_PORT)
}
pub fn get_tcp_request_timeout(&self) -> Duration {
Duration::from_secs(
self.tcp_request_timeout
.unwrap_or(DEFAULT_TCP_REQUEST_TIMEOUT),
)
}
pub fn get_log_level(&self) -> tracing::Level {
if let Some(ref level_str) = self.log_level {
tracing::Level::from_str(level_str).unwrap_or(tracing::Level::INFO)
} else {
tracing::Level::INFO
}
}
pub fn get_directory(&self) -> &Path {
self.directory
.as_ref()
.map_or(Path::new(DEFAULT_PATH), Path::new)
}
pub fn get_zones(&self) -> &[ZoneConfig] {
&self.zones
}
pub fn get_tls_cert(&self) -> Option<&dnssec::TlsCertConfig> {
cfg_if! {
if #[cfg(feature = "dnssec")] {
self.tls_cert.as_ref()
} else {
None
}
}
}
}
impl FromStr for Config {
type Err = ConfigError;
fn from_str(toml: &str) -> ConfigResult<Self> {
toml::de::from_str(toml).map_err(Into::into)
}
}
#[derive(Deserialize, PartialEq, Eq, Debug)]
pub struct ZoneConfig {
pub zone: String, pub zone_type: ZoneType,
pub file: Option<String>,
pub allow_update: Option<bool>,
pub allow_axfr: Option<bool>,
pub enable_dnssec: Option<bool>,
#[serde(default)]
pub keys: Vec<dnssec::KeyConfig>,
#[serde(default)]
pub stores: Option<StoreConfig>,
}
impl ZoneConfig {
pub fn new(
zone: String,
zone_type: ZoneType,
file: String,
allow_update: Option<bool>,
allow_axfr: Option<bool>,
enable_dnssec: Option<bool>,
keys: Vec<dnssec::KeyConfig>,
) -> Self {
Self {
zone,
zone_type,
file: Some(file),
allow_update,
allow_axfr,
enable_dnssec,
keys,
stores: None,
}
}
pub fn get_zone(&self) -> ProtoResult<Name> {
Name::parse(&self.zone, Some(&Name::new()))
}
pub fn get_zone_type(&self) -> ZoneType {
self.zone_type
}
pub fn get_file(&self) -> PathBuf {
PathBuf::from(self.file.as_ref().expect("file was none"))
}
pub fn is_update_allowed(&self) -> bool {
self.allow_update.unwrap_or(false)
}
pub fn is_axfr_allowed(&self) -> bool {
self.allow_axfr.unwrap_or(false)
}
pub fn is_dnssec_enabled(&self) -> bool {
cfg_if! {
if #[cfg(feature = "dnssec")] {
self.enable_dnssec.unwrap_or(false)
} else {
false
}
}
}
#[cfg(feature = "dnssec")]
#[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
pub fn get_keys(&self) -> &[dnssec::KeyConfig] {
&self.keys
}
}