mirror of
https://github.com/speatzle/nfsense.git
synced 2025-05-10 18:38:22 +00:00
Implement Kea DHCP v4
This commit is contained in:
parent
f43e44c820
commit
142e85f08f
5 changed files with 268 additions and 7 deletions
|
@ -269,6 +269,7 @@ export const editTypes: { [key: string]: { [key: string]: any } } = {
|
|||
name: 'DHCP Server',
|
||||
idType: 'Number',
|
||||
fields: {
|
||||
name: { is: 'TextBox', label: 'Name'},
|
||||
interface: { is: 'SingleSelect', label: 'Interface', props: { searchProvider: GetInterfaces} },
|
||||
pool: { is: 'MultiSelect', label: 'Pool', props: { searchProvider: GetAddresses} },
|
||||
gateway_mode: { is: 'EnumInput', label: 'Gateway Mode', props: { variants: {
|
||||
|
@ -287,7 +288,7 @@ export const editTypes: { [key: string]: { [key: string]: any } } = {
|
|||
'specify': {
|
||||
display: 'Specify',
|
||||
fields: {
|
||||
servers: { is: 'MultiSelect', label: 'DNS Servers', props: { searchProvider: GetAddresses} },
|
||||
dns_servers: { is: 'MultiSelect', label: 'DNS Servers', props: { searchProvider: GetAddresses} },
|
||||
},
|
||||
},
|
||||
}}},
|
||||
|
@ -297,12 +298,11 @@ export const editTypes: { [key: string]: { [key: string]: any } } = {
|
|||
'specify': {
|
||||
display: 'Specify',
|
||||
fields: {
|
||||
servers: { is: 'MultiSelect', label: 'NTP Servers', props: { searchProvider: GetAddresses} },
|
||||
ntp_servers: { is: 'MultiSelect', label: 'NTP Servers', props: { searchProvider: GetAddresses} },
|
||||
},
|
||||
},
|
||||
}}},
|
||||
default_lease_time: { is: 'NumberBox', label: 'Default Lease Time'},
|
||||
max_lease_time: { is: 'NumberBox', label: 'Max Lease Time'},
|
||||
lease_time: { is: 'NumberBox', label: 'Lease Time'},
|
||||
comment: { is: 'MultilineTextBox', label: 'Comment'},
|
||||
},
|
||||
},
|
||||
|
|
257
src/apply/kea.rs
Normal file
257
src/apply/kea.rs
Normal file
|
@ -0,0 +1,257 @@
|
|||
use super::ApplyError;
|
||||
use crate::definitions::{
|
||||
config::Config,
|
||||
network::{AddressingMode, NetworkInterfaceType},
|
||||
object::AddressType,
|
||||
service::{DNSServerMode, GatewayMode, NTPServerMode},
|
||||
};
|
||||
use ipnet::IpNet;
|
||||
use serde::Serialize;
|
||||
use std::io::Write;
|
||||
use std::process::Command;
|
||||
use tracing::info;
|
||||
|
||||
const KEA_V4_CONFIG_PATH: &str = "/etc/kea/kea-dhcp4.conf";
|
||||
// const KEA_V6_CONFIG_PATH: &str = "/etc/kea/kea-dhcp6.conf";
|
||||
|
||||
#[derive(Serialize, Clone, Debug)]
|
||||
pub struct KeaConfig {
|
||||
#[serde(rename = "Dhcp4")]
|
||||
pub dhcpv4: KeaDHCPv4,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone, Debug)]
|
||||
pub struct KeaDHCPv4 {
|
||||
#[serde(rename = "valid-lifetime")]
|
||||
pub valid_lifetime: u64,
|
||||
#[serde(rename = "renew-timer")]
|
||||
pub renew_timer: u64,
|
||||
#[serde(rename = "rebind-timer")]
|
||||
pub rebind_timer: u64,
|
||||
|
||||
#[serde(rename = "interfaces-config")]
|
||||
pub interfaces_config: KeaInterfaces,
|
||||
|
||||
#[serde(rename = "lease-database")]
|
||||
pub lease_database: KeaLeases,
|
||||
|
||||
#[serde(rename = "subnet4")]
|
||||
pub subnet4: Vec<KeaSubnet4>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone, Debug)]
|
||||
pub struct KeaInterfaces {
|
||||
#[serde(rename = "interfaces")]
|
||||
pub interfaces: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone, Debug)]
|
||||
pub struct KeaLeases {
|
||||
#[serde(rename = "type")]
|
||||
pub database_type: String,
|
||||
#[serde(rename = "persist")]
|
||||
pub persist: bool,
|
||||
#[serde(rename = "name")]
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone, Debug)]
|
||||
pub struct KeaSubnet4 {
|
||||
// TODO add subnet Id https://kea.readthedocs.io/en/kea-2.2.0/arm/dhcp4-srv.html#ipv4-subnet-identifier
|
||||
#[serde(rename = "subnet")]
|
||||
pub subnet: IpNet,
|
||||
#[serde(rename = "pools")]
|
||||
pub pools: Vec<KeaPool>,
|
||||
#[serde(rename = "valid-lifetime")]
|
||||
pub valid_lifetime: u64,
|
||||
#[serde(rename = "option-data")]
|
||||
pub option_data: Vec<KeaOption>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone, Debug)]
|
||||
pub struct KeaPool {
|
||||
#[serde(rename = "pool")]
|
||||
pub pool: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone, Debug)]
|
||||
pub struct KeaOption {
|
||||
#[serde(rename = "code")]
|
||||
pub code: u64,
|
||||
#[serde(rename = "data")]
|
||||
pub data: String,
|
||||
}
|
||||
|
||||
pub fn apply_kea(pending_config: Config, _current_config: Config) -> Result<(), ApplyError> {
|
||||
let mut conf: KeaConfig = KeaConfig {
|
||||
dhcpv4: KeaDHCPv4 {
|
||||
valid_lifetime: 4000,
|
||||
renew_timer: 1000,
|
||||
rebind_timer: 2000,
|
||||
interfaces_config: KeaInterfaces { interfaces: vec![] },
|
||||
lease_database: KeaLeases {
|
||||
database_type: "memfile".to_string(),
|
||||
persist: true,
|
||||
name: "/var/lib/kea/dhcp4.leases".to_string(),
|
||||
},
|
||||
subnet4: vec![],
|
||||
},
|
||||
};
|
||||
|
||||
for dhcp_server in pending_config.service.dhcp_servers.clone() {
|
||||
let interface = dhcp_server.interface(pending_config.clone());
|
||||
// TODO specify main ip of interface https://kea.readthedocs.io/en/kea-2.2.0/arm/dhcp4-srv.html#interface-configuration
|
||||
match interface.interface_type {
|
||||
NetworkInterfaceType::Hardware { device } => {
|
||||
conf.dhcpv4.interfaces_config.interfaces.push(device)
|
||||
}
|
||||
_ => conf
|
||||
.dhcpv4
|
||||
.interfaces_config
|
||||
.interfaces
|
||||
.push(interface.name),
|
||||
}
|
||||
|
||||
let mut subnet = KeaSubnet4 {
|
||||
subnet: match interface.addressing_mode {
|
||||
AddressingMode::Static { address } => address.clone(),
|
||||
_ => panic!("Unsupported Addressing mode"),
|
||||
},
|
||||
pools: vec![],
|
||||
valid_lifetime: dhcp_server.lease_time,
|
||||
option_data: vec![],
|
||||
};
|
||||
|
||||
match dhcp_server.gateway_mode.clone() {
|
||||
GatewayMode::Interface => subnet.option_data.push(KeaOption {
|
||||
code: 3,
|
||||
data: match interface.addressing_mode {
|
||||
AddressingMode::Static { address } => address.addr().to_string(),
|
||||
_ => panic!("Unsupported Address Type"),
|
||||
},
|
||||
}),
|
||||
GatewayMode::Specify { .. } => subnet.option_data.push(KeaOption {
|
||||
code: 3,
|
||||
data: match dhcp_server
|
||||
.gateway_mode
|
||||
.gateway(pending_config.clone())
|
||||
.address_type
|
||||
{
|
||||
AddressType::Host { address } => address.to_string(),
|
||||
_ => panic!("Unsupported Address Type"),
|
||||
},
|
||||
}),
|
||||
GatewayMode::None => (),
|
||||
}
|
||||
|
||||
match dhcp_server.dns_server_mode.clone() {
|
||||
DNSServerMode::Interface => subnet.option_data.push(KeaOption {
|
||||
code: 6,
|
||||
data: match interface.addressing_mode {
|
||||
AddressingMode::Static { address } => address.addr().to_string(),
|
||||
_ => panic!("Unsupported Address Type"),
|
||||
},
|
||||
}),
|
||||
DNSServerMode::Specify { .. } => {
|
||||
let mut servers = "".to_string();
|
||||
let dns_servers = dhcp_server
|
||||
.dns_server_mode
|
||||
.dns_servers(pending_config.clone());
|
||||
|
||||
for i in 0..dns_servers.len() {
|
||||
match dns_servers[i].address_type {
|
||||
AddressType::Host { address } => {
|
||||
if i > 0 {
|
||||
servers += ", ";
|
||||
}
|
||||
servers += &address.to_string();
|
||||
}
|
||||
_ => panic!("Unsupported Address Type"),
|
||||
}
|
||||
}
|
||||
|
||||
subnet.option_data.push(KeaOption {
|
||||
code: 6,
|
||||
data: servers,
|
||||
});
|
||||
}
|
||||
DNSServerMode::None => (),
|
||||
}
|
||||
|
||||
match dhcp_server.ntp_server_mode.clone() {
|
||||
NTPServerMode::Interface => subnet.option_data.push(KeaOption {
|
||||
code: 42,
|
||||
data: match interface.addressing_mode {
|
||||
AddressingMode::Static { address } => address.addr().to_string(),
|
||||
_ => panic!("Unsupported Address Type"),
|
||||
},
|
||||
}),
|
||||
NTPServerMode::Specify { .. } => {
|
||||
let mut servers = "".to_string();
|
||||
let ntp_servers = dhcp_server
|
||||
.ntp_server_mode
|
||||
.ntp_servers(pending_config.clone());
|
||||
|
||||
for i in 0..ntp_servers.len() {
|
||||
match ntp_servers[i].address_type {
|
||||
AddressType::Host { address } => {
|
||||
if i > 0 {
|
||||
servers += ", ";
|
||||
}
|
||||
servers += &address.to_string();
|
||||
}
|
||||
_ => panic!("Unsupported Address Type"),
|
||||
}
|
||||
}
|
||||
|
||||
subnet.option_data.push(KeaOption {
|
||||
code: 42,
|
||||
data: servers,
|
||||
});
|
||||
}
|
||||
NTPServerMode::None => (),
|
||||
}
|
||||
|
||||
let pools = dhcp_server.pool(pending_config.clone());
|
||||
for pool in pools {
|
||||
match pool.address_type {
|
||||
AddressType::Host { address } => subnet.pools.push(KeaPool {
|
||||
pool: address.to_string() + "/32",
|
||||
}),
|
||||
AddressType::Range { .. } => panic!("TODO fix range type"),
|
||||
AddressType::Network { network } => subnet.pools.push(KeaPool {
|
||||
pool: network.to_string(),
|
||||
}),
|
||||
AddressType::Group { .. } => panic!("TODO"),
|
||||
}
|
||||
}
|
||||
|
||||
conf.dhcpv4.subnet4.push(subnet);
|
||||
}
|
||||
|
||||
info!("Serializeing Kea v4 Config");
|
||||
let config_data: String = serde_json::to_string_pretty(&conf)?;
|
||||
|
||||
info!("Deleting old Kea v4 Config");
|
||||
std::fs::remove_file(KEA_V4_CONFIG_PATH)?;
|
||||
|
||||
info!("Writing new Kea v4 Config");
|
||||
let mut f = std::fs::File::create(KEA_V4_CONFIG_PATH)?;
|
||||
f.write_all(config_data.as_bytes())?;
|
||||
|
||||
info!("Restarting Kea");
|
||||
match Command::new("systemctl")
|
||||
.arg("restart")
|
||||
.arg("kea-dhcp4")
|
||||
.output()
|
||||
{
|
||||
Ok(out) => {
|
||||
if out.status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ApplyError::ServiceRestartFailed)
|
||||
}
|
||||
}
|
||||
Err(err) => Err(ApplyError::IOError(err)),
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
use thiserror::Error;
|
||||
|
||||
pub mod chrony;
|
||||
pub mod kea;
|
||||
pub mod networkd;
|
||||
pub mod nftables;
|
||||
pub mod unbound;
|
||||
|
@ -16,6 +17,9 @@ pub enum ApplyError {
|
|||
#[error(transparent)]
|
||||
AddrParseError(#[from] ipnet::AddrParseError),
|
||||
|
||||
#[error(transparent)]
|
||||
SerdeError(#[from] serde_json::Error),
|
||||
|
||||
#[error("Service Restart Failed")]
|
||||
ServiceRestartFailed,
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ static APPLY_FUNCTIONS: &'static [fn(
|
|||
) -> Result<(), super::apply::ApplyError>] = &[
|
||||
super::apply::networkd::apply_networkd,
|
||||
super::apply::nftables::apply_nftables,
|
||||
super::apply::kea::apply_kea,
|
||||
super::apply::chrony::apply_chrony,
|
||||
super::apply::unbound::apply_unbound,
|
||||
];
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use core::time;
|
||||
use macaddr::MacAddr8;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
|
@ -15,11 +14,11 @@ pub struct DHCPServer {
|
|||
pub name: String,
|
||||
pub interface: String,
|
||||
pub pool: Vec<String>,
|
||||
pub lease_time: time::Duration,
|
||||
pub lease_time: u64,
|
||||
pub gateway_mode: GatewayMode,
|
||||
pub dns_server_mode: DNSServerMode,
|
||||
pub ntp_server_mode: NTPServerMode,
|
||||
pub reservations: Vec<Reservation>,
|
||||
// pub reservations: Vec<Reservation>,
|
||||
pub comment: String,
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue