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)]
pub struct Storage {
connection: StorageConnectionType,
kind: StorageKind,
size: u64,
serial: String,
pub connection: StorageConnectionType,
pub kind: StorageKind,
pub size: u64,
pub serial: String,
}
#[derive(Debug, Clone)]

View File

@ -47,6 +47,7 @@ pub trait DhcpServer: Send + Sync {
async fn list_static_mappings(&self) -> Vec<(MacAddress, IpAddress)>;
fn get_ip(&self) -> IpAddress;
fn get_host(&self) -> LogicalHost;
async fn commit_config(&self) -> Result<(), ExecutorError>;
}
impl std::fmt::Debug for dyn DhcpServer {

View File

@ -1,9 +1,10 @@
mod management;
use std::sync::{Arc, RwLock };
use std::sync::Arc;
use async_trait::async_trait;
use log::debug;
pub use management::*;
use tokio::sync::RwLock;
use crate::{
executors::ExecutorError,
@ -97,14 +98,24 @@ impl LoadBalancer for OPNSenseFirewall {
#[async_trait]
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> {
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
.dhcp()
.add_static_mapping(&mac, entry.ip, &entry.name).unwrap();
.add_static_mapping(&mac, entry.ip, &entry.name)
.unwrap();
}
debug!("Registered {:?}", entry);

View File

@ -87,7 +87,9 @@ impl Interpret for DhcpInterpret {
.map(|binding| {
let ip = match binding.logical_host.ip {
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 {
@ -99,20 +101,23 @@ impl Interpret for DhcpInterpret {
.collect();
info!("DHCPStaticEntry : {:?}", dhcp_entries);
let dhcp = Arc::new(Box::new(topology.dhcp_server.clone()));
info!("DHCP server : {:?}", dhcp);
let dhcp_server = Arc::new(Box::new(topology.dhcp_server.clone()));
info!("DHCP server : {:?}", dhcp_server);
let number_new_entries = dhcp_entries.len();
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),
Err(_) => todo!(),
}
}
todo!("Configure DHCPServer");
dhcp_server.commit_config().await;
Ok(Outcome::new(
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 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 staticroutes: StaticRoutes,
pub ca: MaybeString,
pub gateways: Option<Gateways>,
pub gateways: Option<RawXml>,
pub cert: Vec<Cert>,
pub dhcpdv6: DhcpDv6,
pub virtualip: VirtualIp,
@ -60,7 +60,6 @@ impl OPNsense {
}
}
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
pub struct LoadBalancer {
pub monitor_type: Vec<MonitorType>,
@ -415,6 +414,8 @@ pub struct OPNsenseXmlSection {
pub ipsec: Option<IPsec>,
#[yaserde(rename = "Interfaces")]
pub interfaces: Option<ConfigInterfaces>,
#[yaserde(rename = "NodeExporter")]
pub node_exporter: Option<RawXml>,
#[yaserde(rename = "Kea")]
pub kea: Option<RawXml>,
pub monit: Option<Monit>,
@ -428,6 +429,7 @@ pub struct OPNsenseXmlSection {
pub unboundplus: Option<RawXml>,
#[yaserde(rename = "DHCRelay")]
pub dhcrelay: Option<RawXml>,
pub trust: Option<RawXml>,
pub wireguard: Option<Wireguard>,
#[yaserde(rename = "Swanctl")]
pub swanctl: Swanctl,
@ -479,6 +481,8 @@ pub struct IDSGeneral {
#[yaserde(rename = "LogPayload")]
log_payload: Option<u8>,
verbosity: MaybeString,
#[yaserde(rename = "eveLog")]
eve_log: Option<RawXml>,
}
#[derive(Debug, YaSerialize, YaDeserialize, PartialEq)]
@ -498,11 +502,15 @@ pub struct IPsec {
key_pairs: MaybeString,
#[yaserde(rename = "preSharedKeys")]
pre_shared_keys: MaybeString,
charon: Option<RawXml>,
}
#[derive(Debug, YaSerialize, YaDeserialize, PartialEq)]
pub struct GeneralIpsec {
enabled: MaybeString,
preferred_oldsa: MaybeString,
disablevpnrules: MaybeString,
passthrough_networks: MaybeString,
}
#[derive(Debug, YaSerialize, YaDeserialize, PartialEq)]
@ -1214,6 +1222,8 @@ pub struct WireguardServerItem {
pub gateway: MaybeString,
pub carp_depend_on: MaybeString,
pub peers: String,
pub endpoint: MaybeString,
pub peer_dns: MaybeString,
}
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
@ -1320,7 +1330,6 @@ pub struct ConfigOpenVPN {
pub StaticKeys: MaybeString,
}
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
#[yaserde(rename = "HAProxy")]
pub struct HAProxy {
@ -1411,6 +1420,8 @@ pub struct Tuning {
#[yaserde(rename = "maxConnections")]
pub max_connections: MaybeString,
pub nbthread: i32,
#[yaserde(rename = "resolversPrefer")]
pub resolvers_prefer: String,
#[yaserde(rename = "sslServerVerify")]
pub ssl_server_verify: String,
#[yaserde(rename = "maxDHSize")]
@ -1425,6 +1436,12 @@ pub struct Tuning {
pub lua_max_mem: i32,
#[yaserde(rename = "customOptions")]
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")]
pub ssl_defaults_enabled: i32,
#[yaserde(rename = "ssl_bindOptions")]
@ -1437,6 +1454,19 @@ pub struct Tuning {
pub ssl_cipher_list: String,
#[yaserde(rename = "ssl_cipherSuites")]
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)]
@ -1684,25 +1714,22 @@ pub struct Backend {
pub http2_enabled_nontls: u8,
#[yaserde(rename = "ba_advertised_protocols")]
pub ba_advertised_protocols: String,
#[yaserde(rename = "persistence")]
pub persistence: String,
#[yaserde(rename = "persistence_cookiemode")]
#[yaserde(rename = "forwardFor")]
pub forward_for: Option<i32>,
#[yaserde(rename = "forwardedHeader")]
pub forwarded_header: Option<MaybeString>,
#[yaserde(rename = "forwardedHeaderParameters")]
pub forwarded_header_parameters: Option<MaybeString>,
pub persistence: MaybeString,
pub persistence_cookiemode: String,
#[yaserde(rename = "persistence_cookiename")]
pub persistence_cookiename: MaybeString,
#[yaserde(rename = "persistence_stripquotes")]
pub persistence_stripquotes: u8,
#[yaserde(rename = "stickiness_pattern")]
pub stickiness_pattern: String,
pub stickiness_pattern: MaybeString,
#[yaserde(rename = "stickiness_dataTypes")]
pub stickiness_data_types: MaybeString,
#[yaserde(rename = "stickiness_expire")]
pub stickiness_expire: String,
#[yaserde(rename = "stickiness_size")]
pub stickiness_size: String,
#[yaserde(rename = "stickiness_cookiename")]
pub stickiness_cookiename: MaybeString,
#[yaserde(rename = "stickiness_cookielength")]
pub stickiness_cookielength: MaybeString,
#[yaserde(rename = "stickiness_connRatePeriod")]
pub stickiness_conn_rate_period: String,
@ -1863,12 +1890,6 @@ pub struct StaticRoutes {
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
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)]
pub struct Cert {
#[yaserde(attribute)]
@ -1975,14 +1996,14 @@ pub struct Bridges {
pub struct Gifs {
#[yaserde(attribute)]
pub version: Option<String>,
pub gif: MaybeString,
pub gif: Option<MaybeString>,
}
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]
pub struct Gres {
#[yaserde(attribute)]
pub version: Option<String>,
pub gre: MaybeString,
pub gre: Option<MaybeString>,
}
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)]

View File

@ -24,9 +24,10 @@ impl SshConfigManager {
impl SshConfigManager {
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
}

View File

@ -84,9 +84,13 @@ impl<'a> DhcpConfig<'a> {
return Err(DhcpError::InvalidMacAddress(mac));
}
if !Self::is_ip_in_range(&ipaddr, range) {
return Err(DhcpError::IpAddressOutOfRange(ipaddr.to_string()));
}
// TODO verify if address is in subnet range
// 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| {
m.ipaddr
@ -123,7 +127,7 @@ impl<'a> DhcpConfig<'a> {
parts
.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 {