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