forked from NationTech/harmony
Merge branch 'master' of https://git.nationtech.io/NationTech/harmony
This commit is contained in:
commit
0b6c8bfd09
35
harmony-rs/Cargo.lock
generated
35
harmony-rs/Cargo.lock
generated
@ -711,6 +711,17 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fqm"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cidr",
|
||||||
|
"env_logger",
|
||||||
|
"harmony",
|
||||||
|
"log",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "funty"
|
name = "funty"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@ -885,6 +896,7 @@ dependencies = [
|
|||||||
"libredfish",
|
"libredfish",
|
||||||
"log",
|
"log",
|
||||||
"opnsense-config",
|
"opnsense-config",
|
||||||
|
"opnsense-config-xml",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"russh",
|
"russh",
|
||||||
"rust-ipmi",
|
"rust-ipmi",
|
||||||
@ -1395,6 +1407,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"uuid",
|
||||||
"xml-rs",
|
"xml-rs",
|
||||||
"yaserde",
|
"yaserde",
|
||||||
"yaserde_derive",
|
"yaserde_derive",
|
||||||
@ -2491,6 +2504,28 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "1.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
"rand",
|
||||||
|
"uuid-macro-internal",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid-macro-internal"
|
||||||
|
version = "1.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6b91f57fe13a38d0ce9e28a03463d8d3c2468ed03d75375110ec71d93b449a08"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.90",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
|||||||
@ -18,3 +18,4 @@ env_logger = { workspace = true }
|
|||||||
async-trait = { workspace = true }
|
async-trait = { workspace = true }
|
||||||
cidr = { workspace = true }
|
cidr = { workspace = true }
|
||||||
opnsense-config = { path = "../opnsense-config" }
|
opnsense-config = { path = "../opnsense-config" }
|
||||||
|
opnsense-config-xml = { path = "../opnsense-config-xml" }
|
||||||
|
|||||||
@ -12,12 +12,14 @@ use super::{
|
|||||||
|
|
||||||
pub enum InterpretName {
|
pub enum InterpretName {
|
||||||
OPNSenseDHCP,
|
OPNSenseDHCP,
|
||||||
|
OPNSenseDns
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for InterpretName {
|
impl std::fmt::Display for InterpretName {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
InterpretName::OPNSenseDHCP => f.write_str("OPNSenseDHCP"),
|
InterpretName::OPNSenseDHCP => f.write_str("OPNSenseDHCP"),
|
||||||
|
InterpretName::OPNSenseDns => f.write_str("OPNSenseDns"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ use std::{net::IpAddr, sync::Arc};
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct HAClusterTopology {
|
pub struct HAClusterTopology {
|
||||||
|
pub domain_name: String,
|
||||||
pub router: Arc<dyn Router>,
|
pub router: Arc<dyn Router>,
|
||||||
pub load_balancer: Arc<dyn LoadBalancer>,
|
pub load_balancer: Arc<dyn LoadBalancer>,
|
||||||
pub firewall: Arc<dyn Firewall>,
|
pub firewall: Arc<dyn Firewall>,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use std::net::Ipv4Addr;
|
use std::{error::Error, net::Ipv4Addr, str::FromStr};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
@ -57,21 +57,35 @@ impl std::fmt::Debug for dyn DhcpServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
pub trait DnsServer: Send + Sync {
|
pub trait DnsServer: Send + Sync {
|
||||||
fn add_record(
|
async fn register_dhcp_leases(&self, register: bool) -> Result<(), ExecutorError>;
|
||||||
&mut self,
|
async fn register_hosts(&self, hosts: Vec<DnsRecord>) -> Result<(), ExecutorError>;
|
||||||
name: &str,
|
|
||||||
record_type: DnsRecordType,
|
|
||||||
value: &str,
|
|
||||||
) -> Result<(), ExecutorError>;
|
|
||||||
fn remove_record(
|
fn remove_record(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
record_type: DnsRecordType,
|
record_type: DnsRecordType,
|
||||||
) -> Result<(), ExecutorError>;
|
) -> Result<(), ExecutorError>;
|
||||||
fn list_records(&self) -> Vec<DnsRecord>;
|
async fn list_records(&self) -> Vec<DnsRecord>;
|
||||||
fn get_ip(&self) -> IpAddress;
|
fn get_ip(&self) -> IpAddress;
|
||||||
fn get_host(&self) -> LogicalHost;
|
fn get_host(&self) -> LogicalHost;
|
||||||
|
async fn commit_config(&self) -> Result<(), ExecutorError>;
|
||||||
|
async fn ensure_hosts_registered(&self, hosts: Vec<DnsRecord>) -> Result<(), ExecutorError> {
|
||||||
|
let current_hosts = self.list_records().await;
|
||||||
|
let mut hosts_to_register = vec![];
|
||||||
|
|
||||||
|
for host in hosts {
|
||||||
|
if !current_hosts.iter().any(|h| h == &host) {
|
||||||
|
hosts_to_register.push(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hosts_to_register.is_empty() {
|
||||||
|
self.register_hosts(hosts_to_register).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for dyn DnsServer {
|
impl std::fmt::Debug for dyn DnsServer {
|
||||||
@ -133,7 +147,7 @@ impl std::fmt::Display for MacAddress {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum DnsRecordType {
|
pub enum DnsRecordType {
|
||||||
A,
|
A,
|
||||||
AAAA,
|
AAAA,
|
||||||
@ -142,9 +156,170 @@ pub enum DnsRecordType {
|
|||||||
TXT,
|
TXT,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
impl std::fmt::Display for DnsRecordType {
|
||||||
pub struct DnsRecord {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
pub name: String,
|
match self {
|
||||||
pub record_type: DnsRecordType,
|
DnsRecordType::A => write!(f, "A"),
|
||||||
pub value: String,
|
DnsRecordType::AAAA => write!(f, "AAAA"),
|
||||||
|
DnsRecordType::CNAME => write!(f, "CNAME"),
|
||||||
|
DnsRecordType::MX => write!(f, "MX"),
|
||||||
|
DnsRecordType::TXT => write!(f, "TXT"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct DnsRecord {
|
||||||
|
pub host: String,
|
||||||
|
pub domain: String,
|
||||||
|
pub record_type: DnsRecordType,
|
||||||
|
pub value: IpAddress,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for DnsRecordType {
|
||||||
|
type Err = String;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"A" => Ok(DnsRecordType::A),
|
||||||
|
"AAAA" => Ok(DnsRecordType::AAAA),
|
||||||
|
"CNAME" => Ok(DnsRecordType::CNAME),
|
||||||
|
"MX" => Ok(DnsRecordType::MX),
|
||||||
|
"TXT" => Ok(DnsRecordType::TXT),
|
||||||
|
_ => Err(format!("Unknown DNSRecordType {s}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_ensure_hosts_registered_no_new_hosts() {
|
||||||
|
let server = DummyDnsServer::default();
|
||||||
|
let existing_host = DnsRecord {
|
||||||
|
host: "existing".to_string(),
|
||||||
|
domain: "example.com".to_string(),
|
||||||
|
record_type: DnsRecordType::A,
|
||||||
|
value: IpAddress::V4(Ipv4Addr::new(192, 168, 1, 2)),
|
||||||
|
};
|
||||||
|
|
||||||
|
server
|
||||||
|
.register_hosts(vec![existing_host.clone()])
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let new_hosts = vec![
|
||||||
|
existing_host, // already exists
|
||||||
|
];
|
||||||
|
|
||||||
|
server.ensure_hosts_registered(new_hosts).await.unwrap();
|
||||||
|
assert_eq!(server.list_records().await.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_ensure_hosts_registered_with_new_hosts() {
|
||||||
|
let server = DummyDnsServer::default();
|
||||||
|
|
||||||
|
let existing_host = DnsRecord {
|
||||||
|
host: "existing".to_string(),
|
||||||
|
domain: "example.com".to_string(),
|
||||||
|
record_type: DnsRecordType::A,
|
||||||
|
value: IpAddress::V4(Ipv4Addr::new(192, 168, 1, 2)),
|
||||||
|
};
|
||||||
|
|
||||||
|
server
|
||||||
|
.register_hosts(vec![existing_host.clone()])
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let new_hosts = vec![
|
||||||
|
existing_host.clone(), // already exists
|
||||||
|
DnsRecord {
|
||||||
|
host: "new".to_string(),
|
||||||
|
domain: "example.com".to_string(),
|
||||||
|
record_type: DnsRecordType::A,
|
||||||
|
value: IpAddress::V4(Ipv4Addr::new(192, 168, 1, 3)),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
server.ensure_hosts_registered(new_hosts).await.unwrap();
|
||||||
|
assert_eq!(server.list_records().await.len(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_ensure_hosts_registered_no_hosts() {
|
||||||
|
let server = DummyDnsServer::default();
|
||||||
|
|
||||||
|
let new_hosts = vec![];
|
||||||
|
|
||||||
|
server.ensure_hosts_registered(new_hosts).await.unwrap();
|
||||||
|
assert_eq!(server.list_records().await.len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_ensure_existing_host_kept_no_new_host() {
|
||||||
|
let server = DummyDnsServer::default();
|
||||||
|
|
||||||
|
let new_hosts = vec![];
|
||||||
|
|
||||||
|
server.ensure_hosts_registered(new_hosts).await.unwrap();
|
||||||
|
assert_eq!(server.list_records().await.len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl DnsServer for DummyDnsServer {
|
||||||
|
async fn register_dhcp_leases(&self, _register: bool) -> Result<(), ExecutorError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn register_hosts(&self, hosts: Vec<DnsRecord>) -> Result<(), ExecutorError> {
|
||||||
|
self.hosts.write().await.extend(hosts);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_record(
|
||||||
|
&mut self,
|
||||||
|
_name: &str,
|
||||||
|
_record_type: DnsRecordType,
|
||||||
|
) -> Result<(), ExecutorError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn list_records(&self) -> Vec<DnsRecord> {
|
||||||
|
self.hosts.read().await.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ip(&self) -> IpAddress {
|
||||||
|
IpAddress::V4(Ipv4Addr::new(192, 168, 0, 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_host(&self) -> LogicalHost {
|
||||||
|
LogicalHost {
|
||||||
|
ip: self.get_ip(),
|
||||||
|
name: "dummy-host".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn commit_config(&self) -> Result<(), ExecutorError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DummyDnsServer {
|
||||||
|
hosts: Arc<RwLock<Vec<DnsRecord>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DummyDnsServer {
|
||||||
|
fn default() -> Self {
|
||||||
|
DummyDnsServer {
|
||||||
|
hosts: Arc::new(RwLock::new(vec![])),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,13 +4,14 @@ use std::sync::Arc;
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
pub use management::*;
|
pub use management::*;
|
||||||
|
use opnsense_config_xml::Host;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
executors::ExecutorError,
|
executors::ExecutorError,
|
||||||
topology::{
|
topology::{
|
||||||
Backend, DHCPStaticEntry, DhcpServer, DnsServer, Firewall, FirewallRule, Frontend,
|
Backend, DHCPStaticEntry, DhcpServer, DnsRecord, DnsServer, Firewall, FirewallRule,
|
||||||
IpAddress, LoadBalancer, LogicalHost,
|
Frontend, IpAddress, LoadBalancer, LogicalHost,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -156,14 +157,24 @@ impl DhcpServer for OPNSenseFirewall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
impl DnsServer for OPNSenseFirewall {
|
impl DnsServer for OPNSenseFirewall {
|
||||||
fn add_record(
|
async fn register_hosts(&self, hosts: Vec<DnsRecord>) -> Result<(), ExecutorError> {
|
||||||
&mut self,
|
let mut writable_opnsense = self.opnsense_config.write().await;
|
||||||
_name: &str,
|
let mut dns = writable_opnsense.dns();
|
||||||
_record_type: crate::topology::DnsRecordType,
|
let hosts = hosts
|
||||||
_value: &str,
|
.iter()
|
||||||
) -> Result<(), ExecutorError> {
|
.map(|h| {
|
||||||
todo!()
|
Host::new(
|
||||||
|
h.host.clone(),
|
||||||
|
h.domain.clone(),
|
||||||
|
h.record_type.to_string(),
|
||||||
|
h.value.to_string(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
dns.register_hosts(hosts);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_record(
|
fn remove_record(
|
||||||
@ -174,8 +185,26 @@ impl DnsServer for OPNSenseFirewall {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_records(&self) -> Vec<crate::topology::DnsRecord> {
|
async fn list_records(&self) -> Vec<crate::topology::DnsRecord> {
|
||||||
todo!()
|
self.opnsense_config
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.dns()
|
||||||
|
.get_hosts()
|
||||||
|
.iter()
|
||||||
|
.map(|h| DnsRecord {
|
||||||
|
host: h.hostname.clone(),
|
||||||
|
domain: h.domain.clone(),
|
||||||
|
record_type: h
|
||||||
|
.rr
|
||||||
|
.parse()
|
||||||
|
.expect("received invalid record type {h.rr} from opnsense"),
|
||||||
|
value: h
|
||||||
|
.server
|
||||||
|
.parse()
|
||||||
|
.expect("received invalid ipv4 record from opnsense {h.server}"),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_ip(&self) -> IpAddress {
|
fn get_ip(&self) -> IpAddress {
|
||||||
@ -185,4 +214,26 @@ impl DnsServer for OPNSenseFirewall {
|
|||||||
fn get_host(&self) -> LogicalHost {
|
fn get_host(&self) -> LogicalHost {
|
||||||
self.host.clone()
|
self.host.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn register_dhcp_leases(&self, register: bool) -> Result<(), ExecutorError> {
|
||||||
|
let mut writable_opnsense = self.opnsense_config.write().await;
|
||||||
|
let mut dns = writable_opnsense.dns();
|
||||||
|
dns.register_dhcp_leases(register);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn commit_config(&self) -> Result<(), ExecutorError> {
|
||||||
|
let opnsense = self.opnsense_config.read().await;
|
||||||
|
|
||||||
|
opnsense
|
||||||
|
.save()
|
||||||
|
.await
|
||||||
|
.map_err(|e| ExecutorError::UnexpectedError(e.to_string()))?;
|
||||||
|
|
||||||
|
opnsense
|
||||||
|
.restart_dns()
|
||||||
|
.await
|
||||||
|
.map_err(|e| ExecutorError::UnexpectedError(e.to_string()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
122
harmony-rs/harmony/src/modules/dns.rs
Normal file
122
harmony-rs/harmony/src/modules/dns.rs
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
use async_trait::async_trait;
|
||||||
|
use derive_new::new;
|
||||||
|
use log::info;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
data::{Id, Version},
|
||||||
|
interpret::{Interpret, InterpretError, InterpretName, InterpretStatus, Outcome},
|
||||||
|
inventory::Inventory,
|
||||||
|
score::Score,
|
||||||
|
topology::{DnsRecord, HAClusterTopology},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, new, Clone)]
|
||||||
|
pub struct DnsScore {
|
||||||
|
dns_entries: Vec<DnsRecord>,
|
||||||
|
register_dhcp_leases: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Score for DnsScore {
|
||||||
|
type InterpretType = DnsInterpret;
|
||||||
|
|
||||||
|
fn create_interpret(self) -> Self::InterpretType {
|
||||||
|
DnsInterpret::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.opnsense.org/manual/dhcp.html#advanced-settings
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DnsInterpret {
|
||||||
|
score: DnsScore,
|
||||||
|
version: Version,
|
||||||
|
id: Id,
|
||||||
|
name: String,
|
||||||
|
status: InterpretStatus,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DnsInterpret {
|
||||||
|
pub fn new(score: DnsScore) -> Self {
|
||||||
|
let version = Version::from("1.0.0").expect("Version should be valid");
|
||||||
|
let name = "DnsInterpret".to_string();
|
||||||
|
let id = Id::from_string(format!("{name}_{version}"));
|
||||||
|
|
||||||
|
Self {
|
||||||
|
version,
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
score,
|
||||||
|
status: InterpretStatus::QUEUED,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async fn serve_dhcp_entries(
|
||||||
|
&self,
|
||||||
|
_inventory: &Inventory,
|
||||||
|
topology: &HAClusterTopology,
|
||||||
|
) -> Result<Outcome, InterpretError> {
|
||||||
|
let dns = topology.dns_server.clone();
|
||||||
|
if let Some(register) = self.score.register_dhcp_leases {
|
||||||
|
dns.register_dhcp_leases(register).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Outcome::new(
|
||||||
|
InterpretStatus::SUCCESS,
|
||||||
|
"DNS Interpret execution successfull".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn ensure_hosts_registered(
|
||||||
|
&self,
|
||||||
|
topology: &HAClusterTopology,
|
||||||
|
) -> Result<Outcome, InterpretError> {
|
||||||
|
let entries = &self.score.dns_entries;
|
||||||
|
topology
|
||||||
|
.dns_server
|
||||||
|
.ensure_hosts_registered(entries.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(Outcome::new(
|
||||||
|
InterpretStatus::SUCCESS,
|
||||||
|
format!(
|
||||||
|
"DnsInterpret registered {} hosts successfully",
|
||||||
|
entries.len()
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Interpret for DnsInterpret {
|
||||||
|
fn get_name(&self) -> InterpretName {
|
||||||
|
InterpretName::OPNSenseDns
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_version(&self) -> crate::domain::data::Version {
|
||||||
|
self.version.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_status(&self) -> InterpretStatus {
|
||||||
|
self.status.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_children(&self) -> Vec<crate::domain::data::Id> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(
|
||||||
|
&self,
|
||||||
|
inventory: &Inventory,
|
||||||
|
topology: &HAClusterTopology,
|
||||||
|
) -> Result<Outcome, InterpretError> {
|
||||||
|
info!("Executing {} on inventory {inventory:?}", self.get_name());
|
||||||
|
|
||||||
|
self.serve_dhcp_entries(inventory, topology).await?;
|
||||||
|
self.ensure_hosts_registered(&topology).await?;
|
||||||
|
|
||||||
|
topology.dns_server.commit_config().await?;
|
||||||
|
|
||||||
|
Ok(Outcome::new(
|
||||||
|
InterpretStatus::SUCCESS,
|
||||||
|
format!("Dns Interpret execution successful"),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,2 +1,3 @@
|
|||||||
pub mod dhcp;
|
pub mod dhcp;
|
||||||
|
pub mod dns;
|
||||||
pub mod okd;
|
pub mod okd;
|
||||||
|
|||||||
48
harmony-rs/harmony/src/modules/okd/dns.rs
Normal file
48
harmony-rs/harmony/src/modules/okd/dns.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
use crate::{
|
||||||
|
modules::dns::DnsScore,
|
||||||
|
score::Score,
|
||||||
|
topology::{DnsRecord, DnsRecordType, HAClusterTopology},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct OKDBootstrapDnsScore {
|
||||||
|
dns_score: DnsScore,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OKDBootstrapDnsScore {
|
||||||
|
pub fn new(topology: &HAClusterTopology) -> Self {
|
||||||
|
let cluster_domain_name = &topology.domain_name;
|
||||||
|
let dns_entries = vec![
|
||||||
|
DnsRecord {
|
||||||
|
host: "api".to_string(),
|
||||||
|
domain: cluster_domain_name.clone(),
|
||||||
|
record_type: DnsRecordType::A,
|
||||||
|
value: topology.dns_server.get_ip(),
|
||||||
|
},
|
||||||
|
DnsRecord {
|
||||||
|
host: "api-int".to_string(),
|
||||||
|
domain: cluster_domain_name.clone(),
|
||||||
|
record_type: DnsRecordType::A,
|
||||||
|
value: topology.dns_server.get_ip(),
|
||||||
|
},
|
||||||
|
DnsRecord {
|
||||||
|
host: "*".to_string(),
|
||||||
|
domain: format!("apps.{}", cluster_domain_name),
|
||||||
|
record_type: DnsRecordType::A,
|
||||||
|
value: topology.dns_server.get_ip(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
Self {
|
||||||
|
dns_score: DnsScore::new(dns_entries, Some(true)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Score for OKDBootstrapDnsScore {
|
||||||
|
type InterpretType = <DnsScore as Score>::InterpretType;
|
||||||
|
|
||||||
|
fn create_interpret(self) -> Self::InterpretType {
|
||||||
|
self.dns_score.create_interpret()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,2 +1,3 @@
|
|||||||
pub mod dhcp;
|
pub mod dhcp;
|
||||||
|
pub mod dns;
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,14 @@ thiserror = "1.0"
|
|||||||
async-trait = { workspace = true }
|
async-trait = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
|
||||||
|
[dependencies.uuid]
|
||||||
|
version = "1.11.0"
|
||||||
|
features = [
|
||||||
|
"v4", # Lets you generate random UUIDs
|
||||||
|
"fast-rng", # Use a faster (but still sufficiently random) RNG
|
||||||
|
"macro-diagnostics", # Enable better diagnostics for compile-time UUIDs
|
||||||
|
]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "1.4.1"
|
pretty_assertions = "1.4.1"
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use crate::{data::dhcpd::DhcpInterface, xml_utils::to_xml_str};
|
use crate::{data::dhcpd::DhcpInterface, xml_utils::to_xml_str};
|
||||||
use log::error;
|
use log::error;
|
||||||
|
use uuid::Uuid;
|
||||||
use yaserde::{MaybeString, NamedList, RawXml};
|
use yaserde::{MaybeString, NamedList, RawXml};
|
||||||
use yaserde_derive::{YaDeserialize, YaSerialize};
|
use yaserde_derive::{YaDeserialize, YaSerialize};
|
||||||
|
|
||||||
@ -426,7 +427,7 @@ pub struct OPNsenseXmlSection {
|
|||||||
pub syslog: Option<ConfigSyslog>,
|
pub syslog: Option<ConfigSyslog>,
|
||||||
#[yaserde(rename = "TrafficShaper")]
|
#[yaserde(rename = "TrafficShaper")]
|
||||||
pub traffic_shaper: Option<RawXml>,
|
pub traffic_shaper: Option<RawXml>,
|
||||||
pub unboundplus: Option<RawXml>,
|
pub unboundplus: Option<UnboundPlus>,
|
||||||
#[yaserde(rename = "DHCRelay")]
|
#[yaserde(rename = "DHCRelay")]
|
||||||
pub dhcrelay: Option<RawXml>,
|
pub dhcrelay: Option<RawXml>,
|
||||||
pub trust: Option<RawXml>,
|
pub trust: Option<RawXml>,
|
||||||
@ -858,17 +859,17 @@ pub struct Proxy {
|
|||||||
|
|
||||||
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
pub struct ConfigGeneral {
|
pub struct ConfigGeneral {
|
||||||
pub enabled: i32,
|
pub enabled: i8,
|
||||||
#[yaserde(rename = "error_pages")]
|
#[yaserde(rename = "error_pages")]
|
||||||
pub error_pages: String,
|
pub error_pages: String,
|
||||||
pub icpPort: MaybeString,
|
pub icpPort: MaybeString,
|
||||||
pub logging: Logging,
|
pub logging: Logging,
|
||||||
pub alternateDNSservers: MaybeString,
|
pub alternateDNSservers: MaybeString,
|
||||||
pub dnsV4First: i32,
|
pub dnsV4First: i8,
|
||||||
pub forwardedForHandling: String,
|
pub forwardedForHandling: String,
|
||||||
pub uriWhitespaceHandling: String,
|
pub uriWhitespaceHandling: String,
|
||||||
pub enablePinger: i32,
|
pub enablePinger: i8,
|
||||||
pub useViaHeader: i32,
|
pub useViaHeader: i8,
|
||||||
pub suppressVersion: i32,
|
pub suppressVersion: i32,
|
||||||
pub connecttimeout: MaybeString,
|
pub connecttimeout: MaybeString,
|
||||||
#[yaserde(rename = "VisibleEmail")]
|
#[yaserde(rename = "VisibleEmail")]
|
||||||
@ -889,8 +890,8 @@ pub struct Logging {
|
|||||||
|
|
||||||
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
pub struct Enable {
|
pub struct Enable {
|
||||||
pub accessLog: i32,
|
pub accessLog: i8,
|
||||||
pub storeLog: i32,
|
pub storeLog: i8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
@ -900,7 +901,7 @@ pub struct Cache {
|
|||||||
|
|
||||||
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
pub struct LocalCache {
|
pub struct LocalCache {
|
||||||
pub enabled: i32,
|
pub enabled: i8,
|
||||||
pub directory: String,
|
pub directory: String,
|
||||||
pub cache_mem: i32,
|
pub cache_mem: i32,
|
||||||
pub maximum_object_size: MaybeString,
|
pub maximum_object_size: MaybeString,
|
||||||
@ -1069,7 +1070,7 @@ pub struct UnboundPlus {
|
|||||||
pub dots: MaybeString,
|
pub dots: MaybeString,
|
||||||
pub hosts: Hosts,
|
pub hosts: Hosts,
|
||||||
pub aliases: MaybeString,
|
pub aliases: MaybeString,
|
||||||
pub domains: MaybeString,
|
pub domains: Option<MaybeString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
@ -1082,9 +1083,9 @@ pub struct UnboundGeneral {
|
|||||||
pub dns64: MaybeString,
|
pub dns64: MaybeString,
|
||||||
pub dns64prefix: MaybeString,
|
pub dns64prefix: MaybeString,
|
||||||
pub noarecords: MaybeString,
|
pub noarecords: MaybeString,
|
||||||
pub regdhcp: i32,
|
pub regdhcp: i8,
|
||||||
pub regdhcpdomain: MaybeString,
|
pub regdhcpdomain: MaybeString,
|
||||||
pub regdhcpstatic: i32,
|
pub regdhcpstatic: i8,
|
||||||
pub noreglladdr6: MaybeString,
|
pub noreglladdr6: MaybeString,
|
||||||
pub noregrecords: MaybeString,
|
pub noregrecords: MaybeString,
|
||||||
pub txtsupport: MaybeString,
|
pub txtsupport: MaybeString,
|
||||||
@ -1096,12 +1097,13 @@ pub struct UnboundGeneral {
|
|||||||
|
|
||||||
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
pub struct Advanced {
|
pub struct Advanced {
|
||||||
pub hideidentity: i32,
|
pub hideidentity: i8,
|
||||||
pub hideversion: i32,
|
pub hideversion: i8,
|
||||||
pub prefetch: i32,
|
pub prefetch: i8,
|
||||||
pub prefetchkey: i32,
|
pub prefetchkey: i8,
|
||||||
pub dnssecstripped: i32,
|
pub dnssecstripped: i8,
|
||||||
pub serveexpired: i32,
|
pub aggressivensec: i8,
|
||||||
|
pub serveexpired: i8,
|
||||||
pub serveexpiredreplyttl: MaybeString,
|
pub serveexpiredreplyttl: MaybeString,
|
||||||
pub serveexpiredttl: MaybeString,
|
pub serveexpiredttl: MaybeString,
|
||||||
pub serveexpiredttlreset: i32,
|
pub serveexpiredttlreset: i32,
|
||||||
@ -1125,6 +1127,7 @@ pub struct Advanced {
|
|||||||
pub numqueriesperthread: MaybeString,
|
pub numqueriesperthread: MaybeString,
|
||||||
pub outgoingrange: MaybeString,
|
pub outgoingrange: MaybeString,
|
||||||
pub jostletimeout: MaybeString,
|
pub jostletimeout: MaybeString,
|
||||||
|
pub discardtimeout: MaybeString,
|
||||||
pub cachemaxttl: MaybeString,
|
pub cachemaxttl: MaybeString,
|
||||||
pub cachemaxnegativettl: MaybeString,
|
pub cachemaxnegativettl: MaybeString,
|
||||||
pub cacheminttl: MaybeString,
|
pub cacheminttl: MaybeString,
|
||||||
@ -1165,18 +1168,34 @@ pub struct Hosts {
|
|||||||
pub hosts: Vec<Host>,
|
pub hosts: Vec<Host>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
#[derive(Default, Clone, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
pub struct Host {
|
pub struct Host {
|
||||||
#[yaserde(attribute)]
|
#[yaserde(attribute)]
|
||||||
pub uuid: String,
|
pub uuid: String,
|
||||||
pub enabled: i32,
|
pub enabled: i8,
|
||||||
pub hostname: String,
|
pub hostname: String,
|
||||||
pub domain: String,
|
pub domain: String,
|
||||||
pub rr: String,
|
pub rr: String,
|
||||||
pub mxprio: MaybeString,
|
pub mxprio: MaybeString,
|
||||||
pub mx: MaybeString,
|
pub mx: MaybeString,
|
||||||
pub server: String,
|
pub server: String,
|
||||||
pub description: String,
|
pub description: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Host {
|
||||||
|
pub fn new(hostname: String, domain: String, rr: String, server: String) -> Self {
|
||||||
|
Host {
|
||||||
|
uuid: Uuid::new_v4().to_string(),
|
||||||
|
enabled: true as i8,
|
||||||
|
hostname,
|
||||||
|
domain,
|
||||||
|
rr,
|
||||||
|
server,
|
||||||
|
mxprio: MaybeString::default(),
|
||||||
|
mx: MaybeString::default(),
|
||||||
|
description: None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
@ -1466,7 +1485,6 @@ pub struct Tuning {
|
|||||||
pub h2_max_concurrent_streams_outgoing: Option<MaybeString>,
|
pub h2_max_concurrent_streams_outgoing: Option<MaybeString>,
|
||||||
#[yaserde(rename = "h2_maxConcurrentStreamsIncoming")]
|
#[yaserde(rename = "h2_maxConcurrentStreamsIncoming")]
|
||||||
pub h2_max_concurrent_streams_incoming: Option<MaybeString>,
|
pub h2_max_concurrent_streams_incoming: Option<MaybeString>,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use std::{net::Ipv4Addr, sync::Arc, time::Duration};
|
use std::{net::Ipv4Addr, sync::Arc, time::Duration};
|
||||||
|
|
||||||
use crate::{config::{SshConfigManager, SshCredentials, SshOPNSenseShell}, error::Error, modules::dhcp::DhcpConfig};
|
use crate::{config::{SshConfigManager, SshCredentials, SshOPNSenseShell}, error::Error, modules::{dhcp::DhcpConfig, dns::DnsConfig}};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use opnsense_config_xml::OPNsense;
|
use opnsense_config_xml::OPNsense;
|
||||||
use russh::client;
|
use russh::client;
|
||||||
@ -35,6 +35,25 @@ impl Config {
|
|||||||
DhcpConfig::new(&mut self.opnsense, self.shell.clone())
|
DhcpConfig::new(&mut self.opnsense, self.shell.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dns(&mut self) -> DnsConfig {
|
||||||
|
DnsConfig::new(&mut self.opnsense, self.shell.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn restart_dns(&self) -> Result<(), Error> {
|
||||||
|
self.shell.exec("configctl unbound restart").await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Save the config to the repository. This method is meant NOT to reload services, only save
|
||||||
|
/// the config to the live file/database and perhaps take a backup when relevant.
|
||||||
|
pub async fn save(&self) -> Result<(), Error> {
|
||||||
|
self.repository
|
||||||
|
.save_config(&self.opnsense.to_xml())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Save the configuration and reload all services. Be careful with this one as it will cause
|
||||||
|
/// downtime in many cases, such as a PPPoE renegociation
|
||||||
pub async fn apply(&self) -> Result<(), Error> {
|
pub async fn apply(&self) -> Result<(), Error> {
|
||||||
self.repository
|
self.repository
|
||||||
.apply_new_config(&self.opnsense.to_xml())
|
.apply_new_config(&self.opnsense.to_xml())
|
||||||
|
|||||||
@ -20,7 +20,11 @@ impl ConfigManager for LocalFileConfigManager {
|
|||||||
Ok(fs::read_to_string(&self.file_path)?)
|
Ok(fs::read_to_string(&self.file_path)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn apply_new_config(&self, content: &str) -> Result<(), Error> {
|
async fn save_config(&self, content: &str) -> Result<(), Error> {
|
||||||
Ok(fs::write(&self.file_path, content)?)
|
Ok(fs::write(&self.file_path, content)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn apply_new_config(&self, content: &str) -> Result<(), Error> {
|
||||||
|
self.save_config(content).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,5 +9,6 @@ use crate::Error;
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait ConfigManager: std::fmt::Debug + Send + Sync {
|
pub trait ConfigManager: std::fmt::Debug + Send + Sync {
|
||||||
async fn load_as_str(&self) -> Result<String, Error>;
|
async fn load_as_str(&self) -> Result<String, Error>;
|
||||||
|
async fn save_config(&self, content: &str) -> Result<(), Error>;
|
||||||
async fn apply_new_config(&self, content: &str) -> Result<(), Error>;
|
async fn apply_new_config(&self, content: &str) -> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,13 +50,18 @@ impl ConfigManager for SshConfigManager {
|
|||||||
self.opnsense_shell.exec("cat /conf/config.xml").await
|
self.opnsense_shell.exec("cat /conf/config.xml").await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn apply_new_config(&self, content: &str) -> Result<(), Error> {
|
async fn save_config(&self, content: &str) -> Result<(), Error> {
|
||||||
let temp_filename = self
|
let temp_filename = self
|
||||||
.opnsense_shell
|
.opnsense_shell
|
||||||
.write_content_to_temp_file(content)
|
.write_content_to_temp_file(content)
|
||||||
.await?;
|
.await?;
|
||||||
self.backup_config_remote().await?;
|
self.backup_config_remote().await?;
|
||||||
self.move_to_live_config(&temp_filename).await?;
|
self.move_to_live_config(&temp_filename).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn apply_new_config(&self, content: &str) -> Result<(), Error> {
|
||||||
|
self.save_config(content).await?;
|
||||||
self.reload_all_services().await?;
|
self.reload_all_services().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use log::info;
|
||||||
use opnsense_config_xml::MaybeString;
|
use opnsense_config_xml::MaybeString;
|
||||||
use opnsense_config_xml::Range;
|
use opnsense_config_xml::Range;
|
||||||
use opnsense_config_xml::StaticMap;
|
use opnsense_config_xml::StaticMap;
|
||||||
@ -93,6 +94,21 @@ impl<'a> DhcpConfig<'a> {
|
|||||||
// return Err(DhcpError::IpAddressOutOfRange(ipaddr.to_string()));
|
// return Err(DhcpError::IpAddressOutOfRange(ipaddr.to_string()));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
if existing_mappings.iter().any(|m| {
|
||||||
|
m.ipaddr
|
||||||
|
.parse::<Ipv4Addr>()
|
||||||
|
.expect("Mapping contains invalid ipv4")
|
||||||
|
== ipaddr
|
||||||
|
&& m.mac == mac
|
||||||
|
}) {
|
||||||
|
info!(
|
||||||
|
"Mapping already exists for {} [{}], skipping",
|
||||||
|
ipaddr.to_string(),
|
||||||
|
mac
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if existing_mappings.iter().any(|m| {
|
if existing_mappings.iter().any(|m| {
|
||||||
m.ipaddr
|
m.ipaddr
|
||||||
.parse::<Ipv4Addr>()
|
.parse::<Ipv4Addr>()
|
||||||
|
|||||||
45
harmony-rs/opnsense-config/src/modules/dns.rs
Normal file
45
harmony-rs/opnsense-config/src/modules/dns.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use opnsense_config_xml::{Host, OPNsense};
|
||||||
|
|
||||||
|
use crate::config::OPNsenseShell;
|
||||||
|
|
||||||
|
pub struct DnsConfig<'a> {
|
||||||
|
opnsense: &'a mut OPNsense,
|
||||||
|
opnsense_shell: Arc<dyn OPNsenseShell>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DnsConfig<'a> {
|
||||||
|
pub fn new(opnsense: &'a mut OPNsense, opnsense_shell: Arc<dyn OPNsenseShell>) -> Self {
|
||||||
|
Self {
|
||||||
|
opnsense,
|
||||||
|
opnsense_shell,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_hosts(&mut self, mut hosts: Vec<Host>) {
|
||||||
|
let unbound = match &mut self.opnsense.opnsense.unboundplus {
|
||||||
|
Some(unbound) => unbound,
|
||||||
|
None => todo!("Handle case where unboundplus is not used"),
|
||||||
|
};
|
||||||
|
unbound.hosts.hosts.append(&mut hosts);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_hosts(&self) -> Vec<Host> {
|
||||||
|
let unbound = match &self.opnsense.opnsense.unboundplus {
|
||||||
|
Some(unbound) => unbound,
|
||||||
|
None => todo!("Handle case where unboundplus is not used"),
|
||||||
|
};
|
||||||
|
unbound.hosts.hosts.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_dhcp_leases(&mut self, register: bool) {
|
||||||
|
let unbound = match &mut self.opnsense.opnsense.unboundplus {
|
||||||
|
Some(unbound) => unbound,
|
||||||
|
None => todo!("Handle case where unboundplus is not used"),
|
||||||
|
};
|
||||||
|
|
||||||
|
unbound.general.regdhcp = register as i8;
|
||||||
|
unbound.general.regdhcpstatic = register as i8;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1 +1,2 @@
|
|||||||
pub mod dhcp;
|
pub mod dhcp;
|
||||||
|
pub mod dns;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user