├── .gitignore
├── appx
├── StoreLogo.png
├── SplashScreen.png
├── Square44x44Logo.png
├── Square150x150Logo.png
└── AppxManifest.xml
├── plugin
├── src
│ ├── lib.rs
│ ├── logging.rs
│ ├── config.rs
│ ├── background.rs
│ ├── utils.rs
│ └── plugin.rs
└── Cargo.toml
├── app
├── Cargo.toml
└── src
│ └── main.rs
├── Cargo.toml
├── LICENSE-MIT
├── README.md
├── LICENSE-APACHE
└── Cargo.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 |
3 | /target
4 |
--------------------------------------------------------------------------------
/appx/StoreLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luqmana/wireguard-uwp-rs/HEAD/appx/StoreLogo.png
--------------------------------------------------------------------------------
/appx/SplashScreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luqmana/wireguard-uwp-rs/HEAD/appx/SplashScreen.png
--------------------------------------------------------------------------------
/appx/Square44x44Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luqmana/wireguard-uwp-rs/HEAD/appx/Square44x44Logo.png
--------------------------------------------------------------------------------
/appx/Square150x150Logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luqmana/wireguard-uwp-rs/HEAD/appx/Square150x150Logo.png
--------------------------------------------------------------------------------
/plugin/src/lib.rs:
--------------------------------------------------------------------------------
1 | //! This crate contains the `IVpnPlugIn` implementation for our UWP VPN plugin app.
2 |
3 | #![windows_subsystem = "windows"]
4 | #![allow(non_snake_case)] // Windows naming conventions
5 |
6 | mod background;
7 | mod config;
8 | mod logging;
9 | mod plugin;
10 | mod utils;
11 |
--------------------------------------------------------------------------------
/app/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "wireguard-uwp"
3 | version = "0.1.0"
4 | edition = "2021"
5 | license = "MIT OR Apache-2.0"
6 | description = "Foreground App for managing WireGuard UWP VPN profiles."
7 |
8 | [dependencies]
9 |
10 | [dependencies.windows]
11 | version = "0.28"
12 | features = [
13 | "alloc",
14 | "build",
15 | "std",
16 | "ApplicationModel_Activation",
17 | "Foundation_Collections",
18 | "UI_Xaml_Controls",
19 | "UI_Xaml_Documents",
20 | "UI_Xaml_Media",
21 | "UI_Xaml",
22 | "Win32_System_Com",
23 | ]
24 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 |
3 | members = [
4 | "app",
5 | "plugin",
6 | ]
7 |
8 | [profile.release]
9 | # Enable link-time optimization, eliminates more code and inlines across crate boundaries.
10 | lto = true
11 |
12 | # codegen-units of 1 gives best optimization, but disables parallel building.
13 | codegen-units = 1
14 |
15 | # Includes debug information in release builds. Necessary for profiling. Does not
16 | # slow down the executable.
17 | debug = true
18 |
19 | # The default optimization level is 3 for release mode builds.
20 | # 0 means disable optimization and is the default for debug mode buids.
21 | # (Setting opt-level=1 for debug builds is a good way of speeding them up a bit.)
22 | # "s" means optimize for size, "z" reduces size even more.
23 | opt-level = 3
--------------------------------------------------------------------------------
/plugin/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "wireguard-uwp-plugin"
3 | version = "0.1.0"
4 | edition = "2021"
5 | license = "MIT OR Apache-2.0"
6 | description = "WireGuard UWP VPN plugin."
7 |
8 | [lib]
9 | crate-type = ["cdylib"]
10 |
11 | [dependencies]
12 | base64 = "0.13"
13 | boringtun = "0.3"
14 | ipnetwork = "0.18"
15 | quick-xml = { version = "0.22", features = ["serialize"] }
16 | serde = { version = "1.0", features = ["derive"] }
17 | serde_with = "1.11"
18 | win_etw_macros = "0.1"
19 | win_etw_provider = "0.1"
20 |
21 | [dependencies.windows]
22 | version = "0.28"
23 | features = [
24 | "alloc",
25 | "build",
26 | "std",
27 | "ApplicationModel_Background",
28 | "ApplicationModel_Core",
29 | "Foundation_Collections",
30 | "Networking_Sockets",
31 | "Networking_Vpn",
32 | "Storage_Streams",
33 | "Win32_Foundation",
34 | "Win32_System_Diagnostics_Debug",
35 | "Win32_System_WinRT",
36 | ]
37 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Luqman Aden
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/plugin/src/logging.rs:
--------------------------------------------------------------------------------
1 | //! Logging primitives along with our ETW Trace Provider.
2 |
3 | use win_etw_macros::trace_logging_provider;
4 |
5 | /// The collection of ETW events our plugin emits.
6 | #[allow(non_snake_case)]
7 | #[trace_logging_provider(guid = "c4522a55-401f-4b81-93f9-aa0d1db734c4")]
8 | pub trait WireGuardUWPEvents {
9 | /// `Connect` event emitted once we've successfully connected
10 | #[event(level = "info")]
11 | fn connected(remote_host: &str, remote_port: u16);
12 | /// Event emitted if we've failed during `Connect`
13 | #[event(level = "error")]
14 | fn connect_fail(code: u32, msg: &str);
15 |
16 | /// Event emitted for `Disconnect`
17 | #[event(level = "warn")]
18 | fn disconnect(code: u32, msg: &str);
19 |
20 | // Noisy packet encap/decap events
21 |
22 | /// Packet encap begin event.
23 | /// Indicates how many outgoing packets are ready to be encapsulated.
24 | #[event(level = "verbose")]
25 | fn encapsulate_begin(packets: u32);
26 | /// Packet encap end event.
27 | /// Indicates how many frames we sent to the remote endpoint.
28 | #[event(level = "verbose")]
29 | fn encapsulate_end(frames: u32);
30 |
31 | /// Frame decap begin event.
32 | /// Indicates the size of the frame received from the remote endpoint.
33 | #[event(level = "verbose")]
34 | fn decapsulate_begin(frame_sz: u32);
35 | /// Frame decap end event.
36 | /// Indicates how many packets were decapsulated and how many frames sent to the remote.
37 | #[event(level = "verbose")]
38 | fn decapsulate_end(packets: u32, control_frames: u32);
39 |
40 | /// KeepAlive packet event.
41 | /// Indicates how many bytes destined for remote.
42 | #[event(level = "info")]
43 | fn keepalive(packet_sz: u32);
44 | }
45 |
--------------------------------------------------------------------------------
/appx/AppxManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
12 | WireGuard UWP VPN
13 | Publisher
14 | StoreLogo.png
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
26 |
27 |
28 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | wireguard_uwp_plugin.dll
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/plugin/src/config.rs:
--------------------------------------------------------------------------------
1 | //! Config parsing.
2 |
3 | use std::net::IpAddr;
4 |
5 | use boringtun::crypto::x25519::{X25519PublicKey, X25519SecretKey};
6 | use ipnetwork::IpNetwork;
7 | use serde::Deserialize;
8 | use serde_with::{serde_as, DisplayFromStr};
9 |
10 | /// A fully-parsed config
11 | #[derive(Deserialize)]
12 | #[serde(rename_all = "PascalCase")]
13 | pub struct WireGuardConfig {
14 | /// Local interface configuration
15 | pub interface: InterfaceConfig,
16 |
17 | /// Remote peer configuration
18 | pub peer: PeerConfig,
19 | }
20 |
21 | impl WireGuardConfig {
22 | /// Parse the config from the given string or return an error.
23 | pub fn from_str(s: &str) -> Result {
24 | quick_xml::de::from_str(s)
25 | }
26 | }
27 |
28 | /// Local VPN interface specific configuration
29 | #[serde_as]
30 | #[derive(Deserialize)]
31 | #[serde(rename_all = "PascalCase")]
32 | pub struct InterfaceConfig {
33 | /// Our local private key
34 | #[serde_as(as = "DisplayFromStr")]
35 | pub private_key: X25519SecretKey,
36 |
37 | /// Addresses to assign to local VPN interface
38 | pub address: Vec,
39 |
40 | /// DNS servers
41 | #[serde(default)]
42 | #[serde(rename = "DNS")]
43 | pub dns_servers: Vec,
44 |
45 | /// DNS Search Domains
46 | #[serde(default)]
47 | #[serde(rename = "DNSSearch")]
48 | pub search_domains: Vec,
49 | }
50 |
51 | /// Remote peer specific configuration
52 | #[serde_as]
53 | #[derive(Deserialize)]
54 | #[serde(rename_all = "PascalCase")]
55 | pub struct PeerConfig {
56 | /// The remote endpoint's public key
57 | #[serde_as(as = "DisplayFromStr")]
58 | pub public_key: X25519PublicKey,
59 |
60 | /// The port the remote endpoint is listening
61 | pub port: u16,
62 |
63 | /// The list of addresses that will get routed to the remote endpoint
64 | #[serde(rename = "AllowedIPs")]
65 | pub allowed_ips: Vec,
66 |
67 | /// The list of addresses that won't get routed to the remote endpoint
68 | #[serde(default)]
69 | #[serde(rename = "ExcludedIPs")]
70 | pub excluded_ips: Vec,
71 |
72 | /// The interval at which to send KeepAlive packets.
73 | pub persistent_keepalive: Option,
74 |
75 | /// An optional pre-shared key to enable an additional layer of security
76 | #[serde(default)]
77 | #[serde(deserialize_with = "from_base64")]
78 | pub preshared_key: Option<[u8; 32]>,
79 | }
80 |
81 | /// Try to parse the base64 encoded pre-shared key from the config
82 | /// into the raw bytes it represents.
83 | fn from_base64<'de, D>(deserializer: D) -> Result