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}