feat: OKD Dhcp config works and is actually savec on opnsense firewall, its alive!! First real run on wk cluster

This commit is contained in:
Jean-Gabriel Gill-Couture 2024-12-17 15:15:41 -05:00
parent d0d81af796
commit b15df3c93f
10 changed files with 132 additions and 41 deletions

View File

@ -96,10 +96,10 @@ pub enum StorageKind {
} }
#[derive(Debug, new, Clone)] #[derive(Debug, new, Clone)]
pub struct Storage { pub struct Storage {
connection: StorageConnectionType, pub connection: StorageConnectionType,
kind: StorageKind, pub kind: StorageKind,
size: u64, pub size: u64,
serial: String, pub serial: String,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View File

@ -47,6 +47,7 @@ pub trait DhcpServer: Send + Sync {
async fn list_static_mappings(&self) -> Vec<(MacAddress, IpAddress)>; async fn list_static_mappings(&self) -> Vec<(MacAddress, IpAddress)>;
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>;
} }
impl std::fmt::Debug for dyn DhcpServer { impl std::fmt::Debug for dyn DhcpServer {

View File

@ -1,9 +1,10 @@
mod management; mod management;
use std::sync::{Arc, RwLock }; 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 tokio::sync::RwLock;
use crate::{ use crate::{
executors::ExecutorError, executors::ExecutorError,
@ -97,14 +98,24 @@ impl LoadBalancer for OPNSenseFirewall {
#[async_trait] #[async_trait]
impl DhcpServer for OPNSenseFirewall { impl DhcpServer for OPNSenseFirewall {
async fn commit_config(&self) -> Result<(), ExecutorError> {
self.opnsense_config
.read()
.await
.apply()
.await
.map_err(|e| ExecutorError::UnexpectedError(e.to_string()))
}
async fn add_static_mapping(&self, entry: &DHCPStaticEntry) -> Result<(), ExecutorError> { async fn add_static_mapping(&self, entry: &DHCPStaticEntry) -> Result<(), ExecutorError> {
let mac: String = String::from(&entry.mac); let mac: String = String::from(&entry.mac);
{ {
let mut writable_opnsense = self.opnsense_config.write().unwrap(); let mut writable_opnsense = self.opnsense_config.write().await;
writable_opnsense writable_opnsense
.dhcp() .dhcp()
.add_static_mapping(&mac, entry.ip, &entry.name).unwrap(); .add_static_mapping(&mac, entry.ip, &entry.name)
.unwrap();
} }
debug!("Registered {:?}", entry); debug!("Registered {:?}", entry);

View File

@ -87,7 +87,9 @@ impl Interpret for DhcpInterpret {
.map(|binding| { .map(|binding| {
let ip = match binding.logical_host.ip { let ip = match binding.logical_host.ip {
std::net::IpAddr::V4(ipv4) => ipv4, std::net::IpAddr::V4(ipv4) => ipv4,
std::net::IpAddr::V6(_) => unimplemented!("DHCPStaticEntry only supports ipv4 at the moment"), std::net::IpAddr::V6(_) => {
unimplemented!("DHCPStaticEntry only supports ipv4 at the moment")
}
}; };
DHCPStaticEntry { DHCPStaticEntry {
@ -99,20 +101,23 @@ impl Interpret for DhcpInterpret {
.collect(); .collect();
info!("DHCPStaticEntry : {:?}", dhcp_entries); info!("DHCPStaticEntry : {:?}", dhcp_entries);
let dhcp = Arc::new(Box::new(topology.dhcp_server.clone())); let dhcp_server = Arc::new(Box::new(topology.dhcp_server.clone()));
info!("DHCP server : {:?}", dhcp); info!("DHCP server : {:?}", dhcp_server);
let number_new_entries = dhcp_entries.len();
for entry in dhcp_entries.into_iter() { for entry in dhcp_entries.into_iter() {
match dhcp.add_static_mapping(&entry).await { match dhcp_server.add_static_mapping(&entry).await {
Ok(_) => info!("Successfully registered DHCPStaticEntry {}", entry), Ok(_) => info!("Successfully registered DHCPStaticEntry {}", entry),
Err(_) => todo!(), Err(_) => todo!(),
} }
} }
todo!("Configure DHCPServer"); dhcp_server.commit_config().await;
Ok(Outcome::new( Ok(Outcome::new(
InterpretStatus::SUCCESS, InterpretStatus::SUCCESS,
"Connection test successful".to_string(), format!("Dhcp Interpret registered {} entries", number_new_entries),
)) ))
} }
} }

View File

@ -1 +1,2 @@
pub mod dhcp; pub mod dhcp;
pub mod okd;

View File

@ -0,0 +1,45 @@
use crate::{
inventory::Inventory,
modules::dhcp::DhcpScore,
score::Score,
topology::{HAClusterTopology, HostBinding},
};
#[derive(Debug)]
pub struct OKDBootstrapDhcpScore {
dhcp_score: DhcpScore,
}
impl OKDBootstrapDhcpScore {
pub fn new(topology: &HAClusterTopology, inventory: &Inventory) -> Self {
Self {
dhcp_score: DhcpScore::new(
topology
.control_plane
.iter()
.enumerate()
.map(|(index, topology_entry)| {
HostBinding {
logical_host: topology_entry.clone(),
physical_host: inventory
.control_plane_host
.get(index)
.expect(
"Iventory should contain at least as many physical hosts as topology",
)
.clone(),
}
})
.collect(),
),
}
}
}
impl Score for OKDBootstrapDhcpScore {
type InterpretType = <DhcpScore as Score>::InterpretType;
fn create_interpret(self) -> Self::InterpretType {
self.dhcp_score.create_interpret()
}
}

View File

@ -0,0 +1,2 @@
pub mod dhcp;

View File

@ -27,7 +27,7 @@ pub struct OPNsense {
pub opnsense: OPNsenseXmlSection, pub opnsense: OPNsenseXmlSection,
pub staticroutes: StaticRoutes, pub staticroutes: StaticRoutes,
pub ca: MaybeString, pub ca: MaybeString,
pub gateways: Option<Gateways>, pub gateways: Option<RawXml>,
pub cert: Vec<Cert>, pub cert: Vec<Cert>,
pub dhcpdv6: DhcpDv6, pub dhcpdv6: DhcpDv6,
pub virtualip: VirtualIp, pub virtualip: VirtualIp,
@ -60,7 +60,6 @@ impl OPNsense {
} }
} }
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
pub struct LoadBalancer { pub struct LoadBalancer {
pub monitor_type: Vec<MonitorType>, pub monitor_type: Vec<MonitorType>,
@ -415,6 +414,8 @@ pub struct OPNsenseXmlSection {
pub ipsec: Option<IPsec>, pub ipsec: Option<IPsec>,
#[yaserde(rename = "Interfaces")] #[yaserde(rename = "Interfaces")]
pub interfaces: Option<ConfigInterfaces>, pub interfaces: Option<ConfigInterfaces>,
#[yaserde(rename = "NodeExporter")]
pub node_exporter: Option<RawXml>,
#[yaserde(rename = "Kea")] #[yaserde(rename = "Kea")]
pub kea: Option<RawXml>, pub kea: Option<RawXml>,
pub monit: Option<Monit>, pub monit: Option<Monit>,
@ -428,6 +429,7 @@ pub struct OPNsenseXmlSection {
pub unboundplus: Option<RawXml>, pub unboundplus: Option<RawXml>,
#[yaserde(rename = "DHCRelay")] #[yaserde(rename = "DHCRelay")]
pub dhcrelay: Option<RawXml>, pub dhcrelay: Option<RawXml>,
pub trust: Option<RawXml>,
pub wireguard: Option<Wireguard>, pub wireguard: Option<Wireguard>,
#[yaserde(rename = "Swanctl")] #[yaserde(rename = "Swanctl")]
pub swanctl: Swanctl, pub swanctl: Swanctl,
@ -479,6 +481,8 @@ pub struct IDSGeneral {
#[yaserde(rename = "LogPayload")] #[yaserde(rename = "LogPayload")]
log_payload: Option<u8>, log_payload: Option<u8>,
verbosity: MaybeString, verbosity: MaybeString,
#[yaserde(rename = "eveLog")]
eve_log: Option<RawXml>,
} }
#[derive(Debug, YaSerialize, YaDeserialize, PartialEq)] #[derive(Debug, YaSerialize, YaDeserialize, PartialEq)]
@ -498,11 +502,15 @@ pub struct IPsec {
key_pairs: MaybeString, key_pairs: MaybeString,
#[yaserde(rename = "preSharedKeys")] #[yaserde(rename = "preSharedKeys")]
pre_shared_keys: MaybeString, pre_shared_keys: MaybeString,
charon: Option<RawXml>,
} }
#[derive(Debug, YaSerialize, YaDeserialize, PartialEq)] #[derive(Debug, YaSerialize, YaDeserialize, PartialEq)]
pub struct GeneralIpsec { pub struct GeneralIpsec {
enabled: MaybeString, enabled: MaybeString,
preferred_oldsa: MaybeString,
disablevpnrules: MaybeString,
passthrough_networks: MaybeString,
} }
#[derive(Debug, YaSerialize, YaDeserialize, PartialEq)] #[derive(Debug, YaSerialize, YaDeserialize, PartialEq)]
@ -1214,6 +1222,8 @@ pub struct WireguardServerItem {
pub gateway: MaybeString, pub gateway: MaybeString,
pub carp_depend_on: MaybeString, pub carp_depend_on: MaybeString,
pub peers: String, pub peers: String,
pub endpoint: MaybeString,
pub peer_dns: MaybeString,
} }
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
@ -1320,7 +1330,6 @@ pub struct ConfigOpenVPN {
pub StaticKeys: MaybeString, pub StaticKeys: MaybeString,
} }
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
#[yaserde(rename = "HAProxy")] #[yaserde(rename = "HAProxy")]
pub struct HAProxy { pub struct HAProxy {
@ -1411,6 +1420,8 @@ pub struct Tuning {
#[yaserde(rename = "maxConnections")] #[yaserde(rename = "maxConnections")]
pub max_connections: MaybeString, pub max_connections: MaybeString,
pub nbthread: i32, pub nbthread: i32,
#[yaserde(rename = "resolversPrefer")]
pub resolvers_prefer: String,
#[yaserde(rename = "sslServerVerify")] #[yaserde(rename = "sslServerVerify")]
pub ssl_server_verify: String, pub ssl_server_verify: String,
#[yaserde(rename = "maxDHSize")] #[yaserde(rename = "maxDHSize")]
@ -1425,6 +1436,12 @@ pub struct Tuning {
pub lua_max_mem: i32, pub lua_max_mem: i32,
#[yaserde(rename = "customOptions")] #[yaserde(rename = "customOptions")]
pub custom_options: MaybeString, pub custom_options: MaybeString,
#[yaserde(rename = "ocspUpdateEnabled")]
pub ocs_update_enabled: MaybeString,
#[yaserde(rename = "ocspUpdateMinDelay")]
pub ocs_update_min_delay: MaybeString,
#[yaserde(rename = "ocspUpdateMaxDelay")]
pub ocs_update_max_delay: MaybeString,
#[yaserde(rename = "ssl_defaultsEnabled")] #[yaserde(rename = "ssl_defaultsEnabled")]
pub ssl_defaults_enabled: i32, pub ssl_defaults_enabled: i32,
#[yaserde(rename = "ssl_bindOptions")] #[yaserde(rename = "ssl_bindOptions")]
@ -1437,6 +1454,19 @@ pub struct Tuning {
pub ssl_cipher_list: String, pub ssl_cipher_list: String,
#[yaserde(rename = "ssl_cipherSuites")] #[yaserde(rename = "ssl_cipherSuites")]
pub ssl_cipher_suites: String, pub ssl_cipher_suites: String,
#[yaserde(rename = "h2_initialWindowSize")]
pub h2_initial_window_size: Option<MaybeString>,
#[yaserde(rename = "h2_initialWindowSizeOutgoing")]
pub h2_initial_window_size_outgoing: Option<MaybeString>,
#[yaserde(rename = "h2_initialWindowSizeIncoming")]
pub h2_initial_window_size_incoming: Option<MaybeString>,
#[yaserde(rename = "h2_maxConcurrentStreams")]
pub h2_max_concurrent_streams: Option<MaybeString>,
#[yaserde(rename = "h2_maxConcurrentStreamsOutgoing")]
pub h2_max_concurrent_streams_outgoing: Option<MaybeString>,
#[yaserde(rename = "h2_maxConcurrentStreamsIncoming")]
pub h2_max_concurrent_streams_incoming: Option<MaybeString>,
} }
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
@ -1684,25 +1714,22 @@ pub struct Backend {
pub http2_enabled_nontls: u8, pub http2_enabled_nontls: u8,
#[yaserde(rename = "ba_advertised_protocols")] #[yaserde(rename = "ba_advertised_protocols")]
pub ba_advertised_protocols: String, pub ba_advertised_protocols: String,
#[yaserde(rename = "persistence")] #[yaserde(rename = "forwardFor")]
pub persistence: String, pub forward_for: Option<i32>,
#[yaserde(rename = "persistence_cookiemode")] #[yaserde(rename = "forwardedHeader")]
pub forwarded_header: Option<MaybeString>,
#[yaserde(rename = "forwardedHeaderParameters")]
pub forwarded_header_parameters: Option<MaybeString>,
pub persistence: MaybeString,
pub persistence_cookiemode: String, pub persistence_cookiemode: String,
#[yaserde(rename = "persistence_cookiename")]
pub persistence_cookiename: MaybeString, pub persistence_cookiename: MaybeString,
#[yaserde(rename = "persistence_stripquotes")]
pub persistence_stripquotes: u8, pub persistence_stripquotes: u8,
#[yaserde(rename = "stickiness_pattern")] pub stickiness_pattern: MaybeString,
pub stickiness_pattern: String,
#[yaserde(rename = "stickiness_dataTypes")] #[yaserde(rename = "stickiness_dataTypes")]
pub stickiness_data_types: MaybeString, pub stickiness_data_types: MaybeString,
#[yaserde(rename = "stickiness_expire")]
pub stickiness_expire: String, pub stickiness_expire: String,
#[yaserde(rename = "stickiness_size")]
pub stickiness_size: String, pub stickiness_size: String,
#[yaserde(rename = "stickiness_cookiename")]
pub stickiness_cookiename: MaybeString, pub stickiness_cookiename: MaybeString,
#[yaserde(rename = "stickiness_cookielength")]
pub stickiness_cookielength: MaybeString, pub stickiness_cookielength: MaybeString,
#[yaserde(rename = "stickiness_connRatePeriod")] #[yaserde(rename = "stickiness_connRatePeriod")]
pub stickiness_conn_rate_period: String, pub stickiness_conn_rate_period: String,
@ -1863,12 +1890,6 @@ pub struct StaticRoutes {
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
pub struct Ca {} pub struct Ca {}
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
pub struct Gateways {
#[yaserde(rename = "gateway_item")]
pub gateway_item: RawXml
}
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
pub struct Cert { pub struct Cert {
#[yaserde(attribute)] #[yaserde(attribute)]
@ -1975,14 +1996,14 @@ pub struct Bridges {
pub struct Gifs { pub struct Gifs {
#[yaserde(attribute)] #[yaserde(attribute)]
pub version: Option<String>, pub version: Option<String>,
pub gif: MaybeString, pub gif: Option<MaybeString>,
} }
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
pub struct Gres { pub struct Gres {
#[yaserde(attribute)] #[yaserde(attribute)]
pub version: Option<String>, pub version: Option<String>,
pub gre: MaybeString, pub gre: Option<MaybeString>,
} }
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] #[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]

View File

@ -24,9 +24,10 @@ impl SshConfigManager {
impl SshConfigManager { impl SshConfigManager {
async fn backup_config_remote(&self) -> Result<String, Error> { async fn backup_config_remote(&self) -> Result<String, Error> {
let backup_filename = format!("config_{}.xml", chrono::Local::now().format("%Y%m%d%H%M%S")); let ts = chrono::Utc::now();
let backup_filename = format!("config-{}-harmony.xml", ts.format("%s%.3f"));
self.opnsense_shell.exec(&format!("cp /conf/config.xml /tmp/{}", backup_filename)) self.opnsense_shell.exec(&format!("cp /conf/config.xml /conf/backup/{}", backup_filename))
.await .await
} }

View File

@ -84,9 +84,13 @@ impl<'a> DhcpConfig<'a> {
return Err(DhcpError::InvalidMacAddress(mac)); return Err(DhcpError::InvalidMacAddress(mac));
} }
if !Self::is_ip_in_range(&ipaddr, range) { // TODO verify if address is in subnet range
return Err(DhcpError::IpAddressOutOfRange(ipaddr.to_string())); // This check here does not do what we want to do, as we want to assign static leases
} // outside of the dynamic DHCP pool
//
// if !Self::is_ip_in_range(&ipaddr, range) {
// return Err(DhcpError::IpAddressOutOfRange(ipaddr.to_string()));
// }
if existing_mappings.iter().any(|m| { if existing_mappings.iter().any(|m| {
m.ipaddr m.ipaddr
@ -123,7 +127,7 @@ impl<'a> DhcpConfig<'a> {
parts parts
.iter() .iter()
.all(|part| part.len() == 2 && part.chars().all(|c| c.is_ascii_hexdigit())) .all(|part| part.len() <= 2 && part.chars().all(|c| c.is_ascii_hexdigit()))
} }
fn is_ip_in_range(ip: &Ipv4Addr, range: &Range) -> bool { fn is_ip_in_range(ip: &Ipv4Addr, range: &Range) -> bool {