Skip to main content

fips_core/upper/
config.rs

1//! Upper layer configuration types.
2//!
3//! Configuration for the IPv6 adaptation layer components: TUN interface
4//! and DNS responder.
5
6use serde::{Deserialize, Serialize};
7
8/// Default TUN device name.
9const DEFAULT_TUN_NAME: &str = "fips0";
10
11/// Minimum/default TUN MTU (IPv6 minimum).
12///
13/// Runtime startup may raise an omitted `tun.mtu` to the effective FIPS
14/// IPv6 MTU when the configured transports can carry larger packets.
15pub const DEFAULT_TUN_MTU: u16 = 1280;
16
17/// Default DNS responder bind address.
18///
19/// Loopback by default. The shipped `fips-dns-setup` configures
20/// systemd-resolved with a global drop-in pointing at `[::1]:5354`
21/// (instead of a per-link `resolvectl dns fips0 [<fips0_addr>]:5354`),
22/// which avoids a Linux IPV6_PKTINFO behaviour where self-destined
23/// traffic to a TUN address is attributed to the TUN's ifindex —
24/// causing the mesh-interface filter to silently drop every query.
25///
26/// To expose the responder to mesh peers, set `bind_addr: "::"` in
27/// fips.yaml. The `is_mesh_interface_query` filter in `src/upper/dns.rs`
28/// is still in place to prevent hosts-file alias enumeration in that
29/// mode. See `packaging/common/fips-dns-setup` for backend selection.
30const DEFAULT_DNS_BIND_ADDR: &str = "::1";
31
32/// Default DNS responder port.
33const DEFAULT_DNS_PORT: u16 = 5354;
34
35/// Default DNS record TTL in seconds (5 minutes).
36const DEFAULT_DNS_TTL: u32 = 300;
37
38fn default_true() -> bool {
39    true
40}
41
42/// DNS responder configuration (`dns.*`).
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct DnsConfig {
45    /// Enable DNS responder (`dns.enabled`, default: true).
46    #[serde(default = "default_true")]
47    pub enabled: bool,
48
49    /// Bind address (`dns.bind_addr`).
50    #[serde(default, skip_serializing_if = "Option::is_none")]
51    pub bind_addr: Option<String>,
52
53    /// Port (`dns.port`).
54    #[serde(default, skip_serializing_if = "Option::is_none")]
55    pub port: Option<u16>,
56
57    /// Record TTL in seconds (`dns.ttl`).
58    #[serde(default, skip_serializing_if = "Option::is_none")]
59    pub ttl: Option<u32>,
60}
61
62impl Default for DnsConfig {
63    fn default() -> Self {
64        Self {
65            enabled: true,
66            bind_addr: None,
67            port: None,
68            ttl: None,
69        }
70    }
71}
72
73impl DnsConfig {
74    /// Get the bind address (default: `::1`, IPv6 loopback only).
75    pub fn bind_addr(&self) -> &str {
76        self.bind_addr.as_deref().unwrap_or(DEFAULT_DNS_BIND_ADDR)
77    }
78
79    /// Get the port (default: 5354).
80    pub fn port(&self) -> u16 {
81        self.port.unwrap_or(DEFAULT_DNS_PORT)
82    }
83
84    /// Get the TTL in seconds (default: 300).
85    pub fn ttl(&self) -> u32 {
86        self.ttl.unwrap_or(DEFAULT_DNS_TTL)
87    }
88}
89
90/// TUN interface configuration (`tun.*`).
91#[derive(Debug, Clone, Default, Serialize, Deserialize)]
92pub struct TunConfig {
93    /// Enable TUN interface (`tun.enabled`).
94    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
95    pub enabled: bool,
96
97    /// Device name (`tun.name`).
98    #[serde(default, skip_serializing_if = "Option::is_none")]
99    pub name: Option<String>,
100
101    /// MTU (`tun.mtu`).
102    #[serde(default, skip_serializing_if = "Option::is_none")]
103    pub mtu: Option<u16>,
104}
105
106impl TunConfig {
107    /// Get the device name (default: "fips0").
108    pub fn name(&self) -> &str {
109        self.name.as_deref().unwrap_or(DEFAULT_TUN_NAME)
110    }
111
112    /// Get the MTU (default: 1280).
113    pub fn mtu(&self) -> u16 {
114        self.mtu.unwrap_or(DEFAULT_TUN_MTU)
115    }
116}