1use serde::{Deserialize, Deserializer, Serialize};
4
5use crate::{BaseInterface, InterfaceType, NetworkState};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
29#[non_exhaustive]
30pub struct IpsecInterface {
31 #[serde(flatten)]
32 pub base: BaseInterface,
33 #[serde(skip_serializing_if = "Option::is_none")]
34 pub libreswan: Option<LibreswanConfig>,
35}
36
37impl Default for IpsecInterface {
38 fn default() -> Self {
39 Self {
40 base: BaseInterface {
41 iface_type: InterfaceType::Ipsec,
42 ..Default::default()
43 },
44 libreswan: None,
45 }
46 }
47}
48
49impl IpsecInterface {
50 pub fn new() -> Self {
51 Self::default()
52 }
53
54 pub(crate) fn hide_secrets(&mut self) {
55 if let Some(c) = self.libreswan.as_mut()
56 && c.psk.is_some()
57 {
58 c.psk = Some(NetworkState::PASSWORD_HID_BY_NMSTATE.to_string());
59 }
60 }
61
62 pub(crate) fn sanitize(&mut self, is_desired: bool) {
65 if let Some(ipv4_conf) = self.base.ipv4.as_mut()
66 && ipv4_conf.dhcp == Some(false)
67 && ipv4_conf.enabled
68 && ipv4_conf.enabled_defined
69 {
70 if is_desired {
71 log::info!(
72 "Treating IPv4 `dhcp: false` for IPSec interface {} as \
73 IPv4 disabled",
74 self.base.name.as_str()
75 );
76 }
77 ipv4_conf.enabled = false;
78 ipv4_conf.dhcp = None;
79 }
80 }
81}
82
83#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
84#[serde(deny_unknown_fields)]
85#[non_exhaustive]
86pub struct LibreswanConfig {
87 #[serde(rename = "nm-auto-defaults", default = "default_true")]
91 pub nm_auto_defaults: bool,
92 pub right: String,
93 #[serde(skip_serializing_if = "Option::is_none")]
94 pub rightid: Option<String>,
95 #[serde(skip_serializing_if = "Option::is_none")]
96 pub rightrsasigkey: Option<String>,
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub rightcert: Option<String>,
99 #[serde(skip_serializing_if = "Option::is_none")]
100 pub left: Option<String>,
101 #[serde(skip_serializing_if = "Option::is_none")]
102 pub leftid: Option<String>,
103 #[serde(skip_serializing_if = "Option::is_none")]
104 pub leftrsasigkey: Option<String>,
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub leftcert: Option<String>,
107 #[serde(skip_serializing_if = "Option::is_none")]
108 pub ikev2: Option<String>,
109 #[serde(skip_serializing_if = "Option::is_none")]
111 pub psk: Option<String>,
112 #[serde(skip_serializing_if = "Option::is_none")]
113 pub ikelifetime: Option<String>,
114 #[serde(skip_serializing_if = "Option::is_none")]
115 pub salifetime: Option<String>,
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub ike: Option<String>,
118 #[serde(skip_serializing_if = "Option::is_none")]
119 pub esp: Option<String>,
120 #[serde(
121 skip_serializing_if = "Option::is_none",
122 default,
123 deserialize_with = "crate::deserializer::option_u64_or_string"
124 )]
125 pub dpddelay: Option<u64>,
126 #[serde(
127 skip_serializing_if = "Option::is_none",
128 default,
129 deserialize_with = "crate::deserializer::option_u64_or_string"
130 )]
131 pub dpdtimeout: Option<u64>,
132 #[serde(skip_serializing_if = "Option::is_none")]
133 pub dpdaction: Option<String>,
134 #[serde(
135 skip_serializing_if = "Option::is_none",
136 rename = "ipsec-interface",
137 default,
138 deserialize_with = "parse_ipsec_iface"
139 )]
140 pub ipsec_interface: Option<String>,
141 #[serde(skip_serializing_if = "Option::is_none")]
142 pub authby: Option<String>,
143 #[serde(skip_serializing_if = "Option::is_none")]
144 pub rightsubnet: Option<String>,
145 #[serde(skip_serializing_if = "Option::is_none")]
146 pub rightsubnets: Option<String>,
147 #[serde(skip_serializing_if = "Option::is_none")]
148 pub leftsubnet: Option<String>,
149 #[serde(skip_serializing_if = "Option::is_none")]
150 pub leftsubnets: Option<String>,
151 #[serde(skip_serializing_if = "Option::is_none")]
152 pub leftmodecfgclient: Option<bool>,
153 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
154 pub kind: Option<LibreswanConnectionType>,
155 #[serde(skip_serializing_if = "Option::is_none")]
156 pub hostaddrfamily: Option<LibreswanAddressFamily>,
157 #[serde(skip_serializing_if = "Option::is_none")]
158 pub clientaddrfamily: Option<LibreswanAddressFamily>,
159 #[serde(
160 skip_serializing_if = "Option::is_none",
161 rename = "require-id-on-certificate"
162 )]
163 pub require_id_on_certificate: Option<bool>,
164 #[serde(skip_serializing_if = "Option::is_none")]
165 pub leftsendcert: Option<String>,
166 #[serde(skip_serializing_if = "Option::is_none")]
167 pub rightca: Option<String>,
168 #[serde(skip_serializing_if = "Option::is_none")]
169 pub leftprotoport: Option<String>,
170 #[serde(skip_serializing_if = "Option::is_none")]
171 pub rightprotoport: Option<String>,
172}
173
174fn default_true() -> bool {
175 true
176}
177
178impl LibreswanConfig {
179 pub fn new() -> Self {
180 Self::default()
181 }
182}
183
184impl std::fmt::Debug for LibreswanConfig {
185 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186 f.debug_struct("LibreswanConfig")
187 .field("nm-auto-defaults", &self.nm_auto_defaults)
188 .field("right", &self.right)
189 .field("rightid", &self.rightid)
190 .field("rightrsasigkey", &self.rightrsasigkey)
191 .field("rightcert", &self.rightcert)
192 .field("left", &self.left)
193 .field("leftid", &self.leftid)
194 .field("leftrsasigkey", &self.leftrsasigkey)
195 .field("leftcert", &self.leftcert)
196 .field("ikev2", &self.ikev2)
197 .field(
198 "psk",
199 &Some(NetworkState::PASSWORD_HID_BY_NMSTATE.to_string()),
200 )
201 .field("ikelifetime", &self.ikelifetime)
202 .field("salifetime", &self.salifetime)
203 .field("ike", &self.ike)
204 .field("esp", &self.esp)
205 .field("dpddelay", &self.dpddelay)
206 .field("dpdtimeout", &self.dpdtimeout)
207 .field("dpdaction", &self.dpdaction)
208 .field("ipsec_interface", &self.ipsec_interface)
209 .field("authby", &self.authby)
210 .field("rightsubnet", &self.rightsubnet)
211 .field("rightsubnets", &self.rightsubnets)
212 .field("leftsubnet", &self.leftsubnet)
213 .field("leftsubnets", &self.leftsubnets)
214 .field("leftmodecfgclient", &self.leftmodecfgclient)
215 .field("kind", &self.kind)
216 .field("hostaddrfamily", &self.hostaddrfamily)
217 .field("clientaddrfamily", &self.clientaddrfamily)
218 .field("require_id_on_certificate", &self.require_id_on_certificate)
219 .field("leftsendcert", &self.leftsendcert)
220 .field("rightca", &self.rightca)
221 .field("leftprotoport", &self.leftprotoport)
222 .field("rightprotoport", &self.rightprotoport)
223 .finish()
224 }
225}
226
227fn parse_ipsec_iface<'de, D>(
228 deserializer: D,
229) -> Result<Option<String>, D::Error>
230where
231 D: Deserializer<'de>,
232{
233 let v = serde_json::Value::deserialize(deserializer)?;
234
235 match v {
236 serde_json::Value::Number(d) => {
237 if let Some(d) = d.as_u64() {
238 Ok(Some(d.to_string()))
239 } else {
240 Err(serde::de::Error::custom(
241 "Invalid ipsec-interface value, should be unsigned \
242 integer, string 'yes' or 'no'",
243 ))
244 }
245 }
246 serde_json::Value::String(s) => match s.as_str() {
247 "yes" | "no" => Ok(Some(s)),
248 _ => {
249 if s.parse::<u32>().is_ok() {
250 Ok(Some(s))
251 } else {
252 Err(serde::de::Error::custom(
253 "Invalid ipsec-interface value, should be unsigned \
254 integer, string 'yes' or 'no'",
255 ))
256 }
257 }
258 },
259 _ => Err(serde::de::Error::custom(
260 "Invalid ipsec-interface value, should be unsigned integer, \
261 string 'yes' or 'no'",
262 )),
263 }
264}
265
266#[derive(
267 Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default,
268)]
269#[non_exhaustive]
270#[serde(rename_all = "lowercase")]
271pub enum LibreswanConnectionType {
272 #[default]
273 Tunnel,
274 Transport,
275}
276
277impl std::fmt::Display for LibreswanConnectionType {
278 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
279 write!(
280 f,
281 "{}",
282 match self {
283 Self::Tunnel => "tunnel",
284 Self::Transport => "transport",
285 }
286 )
287 }
288}
289
290#[derive(
291 Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default,
292)]
293#[non_exhaustive]
294#[serde(rename_all = "lowercase")]
295pub enum LibreswanAddressFamily {
296 #[default]
297 Ipv4,
298 Ipv6,
299}
300
301impl std::fmt::Display for LibreswanAddressFamily {
302 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
303 write!(
304 f,
305 "{}",
306 match self {
307 Self::Ipv4 => "ipv4",
308 Self::Ipv6 => "ipv6",
309 }
310 )
311 }
312}