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}