1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
//! # DBus interface proxy for: `net.openvpn.v3.netcfg`
//!
//! This code was generated by `zbus-xmlgen` `3.1.0` from DBus introspection data.
//! Source: `net.openvpn.v3.netcfg.node.xml`.

use crate::{
    log::constants::{LogCategory, LogGroup, LogLevel},
    netcfg::constants::NetCfgChangeType,
};

use zbus::dbus_proxy;

use self::constants::*;

#[dbus_proxy(
    interface = "net.openvpn.v3.netcfg",
    default_service = "net.openvpn.v3.netcfg",
    default_path = "/net/openvpn/v3/netcfg"
)]
trait NetCfgNode {
    /// AddDNS method
    ///
    /// Specifies a array of DNS server addresses that should be added to the list of DNS server of the virtual interface.
    ///
    /// # Arguments
    ///
    /// * `server_list` - An array of DNS server IP addresses.
    #[dbus_proxy(name = "AddDNS")]
    fn add_dns(&self, server_list: &[&str]) -> zbus::Result<()>;

    /// AddDNSSearch method
    ///
    /// Specifies a array of DNS search domains that should be added to the list of DNS search to the network.
    ///
    /// # Arguments
    ///
    /// * `domains` - An array of DNS domains.
    #[dbus_proxy(name = "AddDNSSearch")]
    fn add_dnssearch(&self, domains: &[&str]) -> zbus::Result<()>;

    /// AddIPAddress method
    ///
    /// Adds a new local IP Address to the VPN configuration of the virtual interface.
    ///
    /// # Arguments
    ///
    /// * `ip_address` - The IP address in string representation (e.g. `198.51.100.12` or `2001:db8::23`).
    /// * `prefix` - The prefix length (e.g. `/24` or `/64`).
    /// * `gateway` - The IP address in string representation of the remote gateway inside the VPN.
    /// * `ipv6` - Is the new IP address IPv6 or IPv4.
    #[dbus_proxy(name = "AddIPAddress")]
    fn add_ipaddress(
        &self,
        ip_address: &str,
        prefix: u32,
        gateway: &str,
        ipv6: bool,
    ) -> zbus::Result<()>;

    /// AddNetworks method
    ///
    /// Specifies a array of networks that should be either routed over the VPN or explicitly not routed over the VPN. Conflicts between included and excluded are resolved in the usual longest-prefix matching fashion.
    ///
    /// # Arguments
    ///
    /// * `networks` - An array or network tuples:
    ///   0. `ip_address` - The network IP address (the first IP in the network).
    ///   1. `prefix` - The prefix of the network (e.g. /24 or /64).
    ///   2. `ipv6` - Is this a IPv6 or IPv4 network specification.
    ///   3. `exclude` - If true, exclude (do not route) otherwise include (do route) this network over the VPN.
    fn add_networks(&self, networks: &[(&str, u32, bool, bool)]) -> zbus::Result<()>;

    /// Destroy method
    ///
    /// Removes the virtual interface and undoes the configuration (routes, DNS, tun device configuration). The calling application must close the tun device own its own.
    fn destroy(&self) -> zbus::Result<()>;

    /// Disable method
    ///
    /// Indicates that the interface is temporarily not used by the VPN service. E.g. that the VPN connection is disconnected and currently reconnecting. Note: This is currently not implemented.
    fn disable(&self) -> zbus::Result<()>;

    /// EnableDCO method
    ///
    /// Instantiates DCO device object, which handles DCO functionality.
    ///
    /// # Arguments
    ///
    /// * `dev_name` - A name for net device to be created.
    /// * `proto` - Transport protocol.
    ///
    /// # Returns
    ///
    /// A unique D-Bus object path for DCO device.
    #[dbus_proxy(name = "EnableDCO", object = "DCONode")]
    fn enable_dco(&self, dev_name: &str, proto: OVPNProto);

    /// Establish method
    ///
    /// Uses all the information provided to the interface to setup a tun device and set routes, DNS and interface accordingly. The resulting tun device is returned to the caller.
    ///
    /// # Returns
    /// - The file descriptor corresponding to the new tun device (Unix file descriptors that are passed are not in the D-Bus method signature).
    fn establish(&self) -> zbus::Result<()>;

    /// SetRemoteAddress method
    ///
    /// Set the remote address of the VPN server. This is the address the VPN uses to connect to VPN server. This is used when creating direct routes to the VPN server to avoid routing loops (redirect gateway option).
    ///
    /// # Arguments
    ///
    /// * `ip_address` - The IP address in string representation (e.g. `198.51.100.12` or `2001:db8::23`).
    /// * `ipv6` - Is the new IP address IPv6 or IPv4.
    fn set_remote_address(&self, ip_address: &str, ipv6: bool) -> zbus::Result<()>;

    /// Log signal
    #[dbus_proxy(signal)]
    fn log(&self, group: LogGroup, category: LogCategory, message: &str) -> zbus::Result<()>;

    /// NetworkChange signal
    ///
    /// This signal indicates that something has changed in the systems network configuration. These signals will be tied to the interface which triggered this change.
    #[dbus_proxy(signal)]
    fn network_change(
        &self,
        type_: NetCfgChangeType,
        device: &str,
        details: std::collections::HashMap<&str, &str>,
    ) -> zbus::Result<()>;

    /// An array of UID values granted access.
    #[dbus_proxy(property, name = "acl")]
    fn acl(&self) -> zbus::Result<Vec<u32>>;

    /// If the VPN is active (Establish has been successfully called)
    #[dbus_proxy(property, name = "active")]
    fn active(&self) -> zbus::Result<bool>;

    /// Virtual device name used by the session. This may change if the interface needs to be completely reconfigured
    #[dbus_proxy(property, name = "device_name")]
    fn device_name(&self) -> zbus::Result<String>;

    /// List of DNS name servers pushed by the VPN server
    #[dbus_proxy(property, name = "dns_name_servers")]
    fn dns_name_servers(&self) -> zbus::Result<Vec<String>>;

    /// dns_scope property
    #[dbus_proxy(property, name = "dns_scope")]
    fn dns_scope(&self) -> zbus::Result<String>;
    fn set_dns_scope(&self, value: &str) -> zbus::Result<()>;

    /// dns_search_domains property
    #[dbus_proxy(property, name = "dns_search_domains")]
    fn dns_search_domains(&self) -> zbus::Result<Vec<String>>;

    /// OSI layer for the VPN to use, 3 for IP (tun device). Setting to 2 (tap device) is currently not implemented.
    #[dbus_proxy(property, name = "layer")]
    fn layer(&self) -> zbus::Result<u32>;
    fn set_layer(&self, value: u32) -> zbus::Result<()>;

    /// Controls the log verbosity of messages intended to be proxied to the user front-end.
    ///
    /// **Note:** Not currently implemented.
    #[dbus_proxy(property, name = "log_level")]
    fn log_level(&self) -> zbus::Result<LogLevel>;
    fn set_log_level(&self, value: LogLevel) -> zbus::Result<()>;

    /// modified property
    #[dbus_proxy(property, name = "modified")]
    fn modified(&self) -> zbus::Result<bool>;

    /// Sets the MTU for the tun device. Default is `1500`.
    #[dbus_proxy(property, name = "mtu")]
    fn mtu(&self) -> zbus::Result<u32>;
    fn set_mtu(&self, value: u32) -> zbus::Result<()>;

    /// The UID value of the user which created the interface.
    #[dbus_proxy(property, name = "owner")]
    fn owner(&self) -> zbus::Result<u32>;

    /// Setting this to true, tells the service that the default route should be pointed to the VPN and that mechanism to avoid routing loops should be taken.
    #[dbus_proxy(property, name = "reroute_ipv4")]
    fn reroute_ipv4(&self) -> zbus::Result<bool>;
    fn set_reroute_ipv4(&self, value: bool) -> zbus::Result<()>;

    /// As reroute_ipv4 but for IPv6.
    #[dbus_proxy(property, name = "reroute_ipv6")]
    fn reroute_ipv6(&self) -> zbus::Result<bool>;
    fn set_reroute_ipv6(&self, value: bool) -> zbus::Result<()>;

    /// Set the TX queue length of the tun device. If set to 0 or unset, the default from the operating system is used instead.
    #[dbus_proxy(property, name = "txqueuelen")]
    fn txqueuelen(&self) -> zbus::Result<u32>;
    fn set_txqueuelen(&self, value: u32) -> zbus::Result<()>;
}

#[dbus_proxy(
    interface = "net.openvpn.v3.netcfg",
    default_service = "net.openvpn.v3.netcfg",
    default_path = "/net/openvpn/v3/netcfg/_/dco"
)]
trait DCONode {
    /// NewPeer method
    ///
    /// Creates a new peer in the ovpn-dco kernel module. The client is expected to create a socket, establish the connection and pass the remote end-point along with additional properties to this method.
    #[dbus_proxy(name = "NewPeer")]
    fn new_peer(
        &self,
        peer_id: u32,
        sa: &str,
        salen: u32,
        vpn4: &str,
        vpn6: &str,
    ) -> zbus::Result<()>;

    /// GetPipeFD method
    ///
    /// Returns file descriptor used for bidirection generic netlink-based communication with ovpn-dco kernel module.
    #[dbus_proxy(name = "GetPipeFD")]
    fn get_pipe_fd(&self) -> zbus::Result<()>;

    /// NewKey method
    ///
    /// Pass a new symmetric encryption key, along with the cipher to use and its NONCE (if needed). This is used when encrypting and decrypting the tunneled network traffic.
    #[dbus_proxy(name = "NewKey")]
    fn new_key(&self, key_slot: u32, key_config: &str) -> zbus::Result<()>;

    /// SwapKeys method
    ///
    /// Swaps the primary and secondary encryption keys used by the data channel for the tunnelled network traffic. This call triggers instructs ovpn-dco to perform this swap in kernel memory. This is used to rotate and add new symmetric encryption keys during the lifetime of a VPN session. See the OpenVPN documentation related to key renegotiation options for more details.
    #[dbus_proxy(name = "SwapKeys")]
    fn swap_keys(&self, peer_id: u32) -> zbus::Result<()>;

    /// SetPeer method
    ///
    /// Set peer properties in the ovpn-dco kernel module.
    #[dbus_proxy(name = "SetPeer")]
    fn set_peer(
        &self,
        peer_id: u32,
        keepalive_interval: u32,
        keepalive_timeout: u32,
    ) -> zbus::Result<()>;
}

pub mod constants {
    use serde_repr::{Deserialize_repr, Serialize_repr};
    use static_assertions::assert_impl_all;
    use zbus::zvariant::Type;

    #[repr(u8)]
    #[derive(Deserialize_repr, Serialize_repr, Copy, Clone, Type, Debug, PartialEq, Eq)]
    pub enum OVPNProto {
        UDP,
        TCP,
    }

    assert_impl_all!(OVPNProto: Send, Sync, Unpin);
}