use crate::serde_helpers::{ deserialize_bool, deserialize_u16, deserialize_u64, maybe_deserialize_u16, }; use ipnetwork::IpNetwork; use serde::{ de::{Error, Unexpected}, Deserialize, Deserializer, Serialize, Serializer, }; use std::net::IpAddr; #[derive(Debug, Hash, Eq, Clone, PartialEq, Serialize, Deserialize)] #[non_exhaustive] pub enum InterfaceType { #[serde(rename = "vlan")] VLAN, #[serde(rename = "ether")] Ethernet, #[serde(rename = "bridge")] Bridge, #[serde(rename = "wg")] Wireguard, #[serde(rename = "pppoe-out")] PPPoE, #[serde(rename = "6to4-tunnel")] Tunnel6to4, } impl Default for InterfaceType { fn default() -> Self { Self::Ethernet } } #[derive(Debug, Hash, Eq, Clone, PartialEq, Serialize, Deserialize)] #[non_exhaustive] pub enum Mtu { #[serde(rename = "auto")] Auto, Value(u16), } impl Default for Mtu { fn default() -> Self { Self::Auto } } pub fn maybe_deserialize_mtu<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { let s: &str = Deserialize::deserialize(deserializer)?; if s == "auto" { return Ok(Some(Mtu::Auto)); } match s.parse::() { Ok(v) => Ok(Some(Mtu::Value(v))), Err(_) => Err(Error::invalid_value(Unexpected::Str(s), &"an integer")), } } #[derive(Default, Hash, Eq, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Interface { #[serde(rename = ".id")] pub id: String, #[serde(default, rename = "actual-mtu", deserialize_with = "deserialize_u16")] pub actual_mtu: u16, pub comment: Option, #[serde(rename = "default-name")] pub default_name: Option, #[serde(deserialize_with = "deserialize_bool")] pub disabled: bool, #[serde(default, rename = "fp-rx-byte", deserialize_with = "deserialize_u64")] pub fp_rx_byte: u64, #[serde(default, rename = "fp-rx-packet", deserialize_with = "deserialize_u64")] pub fp_rx_packet: u64, #[serde(default, rename = "fp-tx-byte", deserialize_with = "deserialize_u64")] pub fp_tx_byte: u64, #[serde(default, rename = "fp-tx-packet", deserialize_with = "deserialize_u64")] pub fp_tx_packet: u64, #[serde(default, deserialize_with = "deserialize_u16")] pub l2mtu: u16, #[serde(rename = "last-link-up-time")] pub last_link_up_time: Option, #[serde(default, rename = "link-downs", deserialize_with = "deserialize_u16")] pub link_downs: u16, #[serde(rename = "mac-address")] pub mac_address: Option, #[serde( default, rename = "max-l2mtu", deserialize_with = "maybe_deserialize_u16" )] pub max_l2mtu: Option, #[serde(default, deserialize_with = "maybe_deserialize_mtu")] pub mtu: Option, pub name: String, #[serde(deserialize_with = "deserialize_bool")] pub running: bool, #[serde(rename = "rx-byte", deserialize_with = "deserialize_u64")] pub rx_byte: u64, #[serde(rename = "rx-drop", deserialize_with = "deserialize_u64")] pub rx_drop: u64, #[serde(rename = "rx-error", deserialize_with = "deserialize_u64")] pub rx_error: u64, #[serde(rename = "rx-packet", deserialize_with = "deserialize_u64")] pub rx_packet: u64, pub slave: Option, #[serde(rename = "tx-byte", deserialize_with = "deserialize_u64")] pub tx_byte: u64, #[serde(rename = "tx-drop", deserialize_with = "deserialize_u64")] pub tx_drop: u64, #[serde(rename = "tx-error", deserialize_with = "deserialize_u64")] pub tx_error: u64, #[serde(rename = "tx-packet", deserialize_with = "deserialize_u64")] pub tx_packet: u64, #[serde(rename = "tx-queue-drop", deserialize_with = "deserialize_u64")] pub tx_queue_drop: u64, #[serde(rename = "type")] pub type_field: InterfaceType, #[serde(rename = "last-link-down-time")] pub last_link_down_time: Option, } #[derive(Default, Hash, Eq, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct WireguardInterface { #[serde(rename = ".id")] pub id: String, pub comment: String, #[serde(deserialize_with = "deserialize_bool")] pub disabled: bool, #[serde(rename = "listen-port", deserialize_with = "deserialize_u16")] pub listen_port: u16, #[serde(deserialize_with = "deserialize_u16")] pub mtu: u16, pub name: String, #[serde(rename = "private-key")] pub private_key: String, #[serde(rename = "public-key")] pub public_key: String, #[serde(deserialize_with = "deserialize_bool")] pub running: bool, } pub fn de_ip_addr_vector<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let s: &str = Deserialize::deserialize(deserializer)?; let mut answer = vec![]; for addr in s.split(',') { match addr.parse::() { Ok(v) => answer.push(v), Err(_) => { return Err(Error::invalid_value( Unexpected::Str(s), &"an ip address with an optional mask", )) } } } Ok(AllowedAddresses(answer)) } pub fn maybe_ip_addr<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { let s: &str = Deserialize::deserialize(deserializer)?; if s == "" { return Ok(None); } match s.parse::() { Ok(v) => Ok(Some(v)), Err(_) => Err(Error::invalid_value(Unexpected::Str(s), &"an ip address")), } } // TODO(ishan): Make it easier for people to use this! // They should just able to specify it as a string and we can parse it #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct AllowedAddresses(pub Vec); impl Serialize for AllowedAddresses { fn serialize(&self, serializer: S) -> Result where S: Serializer, { let output: Vec = self.0.iter().map(|c| c.to_string()).collect(); let output = output.join(","); serializer.serialize_str(&output) } } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct WireguardPeer { #[serde(rename = ".id")] pub id: String, #[serde(rename = "allowed-address", deserialize_with = "de_ip_addr_vector")] pub allowed_address: AllowedAddresses, #[serde( rename = "current-endpoint-address", deserialize_with = "maybe_ip_addr" )] pub current_endpoint_address: Option, #[serde(rename = "current-endpoint-port", deserialize_with = "deserialize_u16")] pub current_endpoint_port: u16, #[serde(deserialize_with = "deserialize_bool")] pub disabled: bool, #[serde(rename = "endpoint-address", deserialize_with = "maybe_ip_addr")] pub endpoint_address: Option, #[serde(rename = "endpoint-port", deserialize_with = "deserialize_u16")] pub endpoint_port: u16, pub interface: String, #[serde(rename = "last-handshake")] pub last_handshake: Option, #[serde(rename = "persistent-keepalive")] pub persistent_keepalive: Option, #[serde(rename = "public-key")] pub public_key: String, #[serde(deserialize_with = "deserialize_u64")] pub rx: u64, #[serde(deserialize_with = "deserialize_u64")] pub tx: u64, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct AddWireguardPeerInput { #[serde(rename = "allowed-address")] pub allowed_address: AllowedAddresses, pub comment: Option, pub disabled: bool, #[serde(rename = "endpoint-address")] pub endpoint_address: Option, #[serde(rename = "endpoint-port")] pub endpoint_port: u16, pub interface: String, #[serde(rename = "persistent-keepalive")] /// Time in seconds pub persistent_keepalive: Option, #[serde(rename = "preshared-key")] pub preshared_key: Option, #[serde(rename = "public-key")] pub public_key: String, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct AddWireguardPeerOutput { pub ret: String, }