From ae8ea8ae54d14ff5652928ec2701771cc0f6ad56 Mon Sep 17 00:00:00 2001 From: Jett Chen Date: Sun, 12 May 2024 00:08:20 +0800 Subject: [PATCH 1/6] Add toml serde for wireguard config --- .../xcshareddata/swiftpm/Package.resolved | 86 ------------------- Cargo.lock | 53 ++++++++++++ burrow/Cargo.toml | 1 + burrow/src/daemon/instance.rs | 3 + burrow/src/daemon/rpc/request.rs | 1 + burrow/src/wireguard/config.rs | 21 ++++- ...guard__config__tests__tst_config_toml.snap | 16 ++++ 7 files changed, 92 insertions(+), 89 deletions(-) delete mode 100644 Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 burrow/src/wireguard/snapshots/burrow__wireguard__config__tests__tst_config_toml.snap diff --git a/Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index 9378372..0000000 --- a/Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,86 +0,0 @@ -{ - "pins" : [ - { - "identity" : "collectionconcurrencykit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/JohnSundell/CollectionConcurrencyKit.git", - "state" : { - "revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95", - "version" : "0.2.0" - } - }, - { - "identity" : "cryptoswift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/krzyzanowskim/CryptoSwift.git", - "state" : { - "revision" : "7892a123f7e8d0fe62f9f03728b17bbd4f94df5c", - "version" : "1.8.1" - } - }, - { - "identity" : "sourcekitten", - "kind" : "remoteSourceControl", - "location" : "https://github.com/jpsim/SourceKitten.git", - "state" : { - "revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56", - "version" : "0.34.1" - } - }, - { - "identity" : "swift-argument-parser", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-argument-parser.git", - "state" : { - "revision" : "8f4d2753f0e4778c76d5f05ad16c74f707390531", - "version" : "1.2.3" - } - }, - { - "identity" : "swift-syntax", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-syntax.git", - "state" : { - "revision" : "64889f0c732f210a935a0ad7cda38f77f876262d", - "version" : "509.1.1" - } - }, - { - "identity" : "swiftlint", - "kind" : "remoteSourceControl", - "location" : "https://github.com/realm/SwiftLint.git", - "state" : { - "branch" : "main", - "revision" : "7595ad3fafc1a31086dc40ba01fd898bf6b42d5f" - } - }, - { - "identity" : "swiftytexttable", - "kind" : "remoteSourceControl", - "location" : "https://github.com/scottrhoyt/SwiftyTextTable.git", - "state" : { - "revision" : "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3", - "version" : "0.9.0" - } - }, - { - "identity" : "swxmlhash", - "kind" : "remoteSourceControl", - "location" : "https://github.com/drmohundro/SWXMLHash.git", - "state" : { - "revision" : "a853604c9e9a83ad9954c7e3d2a565273982471f", - "version" : "7.0.2" - } - }, - { - "identity" : "yams", - "kind" : "remoteSourceControl", - "location" : "https://github.com/jpsim/Yams.git", - "state" : { - "revision" : "0d9ee7ea8c4ebd4a489ad7a73d5c6cad55d6fed3", - "version" : "5.0.6" - } - } - ], - "version" : 2 -} diff --git a/Cargo.lock b/Cargo.lock index 628e996..03794fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -357,6 +357,7 @@ dependencies = [ "serde", "serde_json", "tokio", + "toml", "tracing", "tracing-journald", "tracing-log 0.1.4", @@ -2102,6 +2103,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2426,6 +2436,40 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +dependencies = [ + "indexmap 2.1.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tonic" version = "0.10.2" @@ -2981,6 +3025,15 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +[[package]] +name = "winnow" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" diff --git a/burrow/Cargo.toml b/burrow/Cargo.toml index 0c816f8..d47b184 100644 --- a/burrow/Cargo.toml +++ b/burrow/Cargo.toml @@ -50,6 +50,7 @@ futures = "0.3.28" once_cell = "1.19" console-subscriber = { version = "0.2.0", optional = true } console = "0.15.8" +toml = "0.8.12" [dependencies.rusqlite] version = "0.31.0" diff --git a/burrow/src/daemon/instance.rs b/burrow/src/daemon/instance.rs index bc506bd..d054e8e 100644 --- a/burrow/src/daemon/instance.rs +++ b/burrow/src/daemon/instance.rs @@ -116,6 +116,9 @@ impl DaemonInstance { .await?; Ok(DaemonResponseData::None) } + DaemonCommand::AddConfigToml(interface_id, config_toml) => { + Ok(DaemonResponseData::None) + } } } diff --git a/burrow/src/daemon/rpc/request.rs b/burrow/src/daemon/rpc/request.rs index e9480aa..ec577c2 100644 --- a/burrow/src/daemon/rpc/request.rs +++ b/burrow/src/daemon/rpc/request.rs @@ -10,6 +10,7 @@ pub enum DaemonCommand { ServerConfig, Stop, ReloadConfig(String), + AddConfigToml(String, String), } #[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)] diff --git a/burrow/src/wireguard/config.rs b/burrow/src/wireguard/config.rs index bd86a9f..2a9dc14 100644 --- a/burrow/src/wireguard/config.rs +++ b/burrow/src/wireguard/config.rs @@ -4,6 +4,7 @@ use anyhow::{anyhow, Error, Result}; use base64::{engine::general_purpose, Engine}; use fehler::throws; use ip_network::IpNetwork; +use serde::{Deserialize, Serialize}; use x25519_dalek::{PublicKey, StaticSecret}; use crate::wireguard::{Interface as WgInterface, Peer as WgPeer}; @@ -31,7 +32,7 @@ fn parse_public_key(string: &str) -> PublicKey { /// A raw version of Peer Config that can be used later to reflect configuration files. /// This should be later converted to a `WgPeer`. /// Refers to https://github.com/pirate/wireguard-docs?tab=readme-ov-file#overview -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct Peer { pub public_key: String, pub preshared_key: Option, @@ -41,7 +42,7 @@ pub struct Peer { pub name: Option, } -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct Interface { pub private_key: String, pub address: Vec, @@ -50,7 +51,7 @@ pub struct Interface { pub mtu: Option, } -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct Config { pub peers: Vec, pub interface: Interface, // Support for multiple interfaces? @@ -113,3 +114,17 @@ impl Default for Config { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn tst_config_toml() { + let cfig = Config::default(); + let toml = toml::to_string(&cfig).unwrap(); + insta::assert_snapshot!(toml); + let cfig2: Config = toml::from_str(&toml).unwrap(); + assert_eq!(cfig, cfig2); + } +} diff --git a/burrow/src/wireguard/snapshots/burrow__wireguard__config__tests__tst_config_toml.snap b/burrow/src/wireguard/snapshots/burrow__wireguard__config__tests__tst_config_toml.snap new file mode 100644 index 0000000..4b6e7b4 --- /dev/null +++ b/burrow/src/wireguard/snapshots/burrow__wireguard__config__tests__tst_config_toml.snap @@ -0,0 +1,16 @@ +--- +source: burrow/src/wireguard/config.rs +expression: toml +--- +[[peers]] +public_key = "8GaFjVO6c4luCHG4ONO+1bFG8tO+Zz5/Gy+Geht1USM=" +preshared_key = "ha7j4BjD49sIzyF9SNlbueK0AMHghlj6+u0G3bzC698=" +allowed_ips = ["8.8.8.8/32", "0.0.0.0/0"] +endpoint = "wg.burrow.rs:51820" + +[interface] +private_key = "OEPVdomeLTxTIBvv3TYsJRge0Hp9NMiY0sIrhT8OWG8=" +address = ["10.13.13.2/24"] +listen_port = 51820 +dns = [] + From dd3f5d0d92493388b71c9661a40cfd7529aa50eb Mon Sep 17 00:00:00 2001 From: Jett Chen Date: Sun, 12 May 2024 00:14:31 +0800 Subject: [PATCH 2/6] Add RPC endpoint for adding toml configs --- burrow/src/daemon/instance.rs | 7 +++++-- burrow/src/daemon/rpc/request.rs | 2 +- burrow/src/database.rs | 4 ++-- burrow/src/wireguard/config.rs | 6 ++++++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/burrow/src/daemon/instance.rs b/burrow/src/daemon/instance.rs index d054e8e..018ec9f 100644 --- a/burrow/src/daemon/instance.rs +++ b/burrow/src/daemon/instance.rs @@ -17,7 +17,7 @@ use crate::{ ServerConfig, ServerInfo, }, - database::{get_connection, load_interface}, + database::{get_connection, load_interface, dump_interface}, wireguard::{Config, Interface}, }; @@ -116,7 +116,10 @@ impl DaemonInstance { .await?; Ok(DaemonResponseData::None) } - DaemonCommand::AddConfigToml(interface_id, config_toml) => { + DaemonCommand::AddConfigToml(config_toml) => { + let conn = get_connection(self.db_path.as_deref())?; + let cfig = Config::from_toml(&config_toml)?; + let _if_id = dump_interface(&conn, &cfig)?; Ok(DaemonResponseData::None) } } diff --git a/burrow/src/daemon/rpc/request.rs b/burrow/src/daemon/rpc/request.rs index ec577c2..0779abb 100644 --- a/burrow/src/daemon/rpc/request.rs +++ b/burrow/src/daemon/rpc/request.rs @@ -10,7 +10,7 @@ pub enum DaemonCommand { ServerConfig, Stop, ReloadConfig(String), - AddConfigToml(String, String), + AddConfigToml(String), } #[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)] diff --git a/burrow/src/database.rs b/burrow/src/database.rs index 0047b01..0dbf397 100644 --- a/burrow/src/database.rs +++ b/burrow/src/database.rs @@ -92,7 +92,7 @@ pub fn load_interface(conn: &Connection, interface_id: &str) -> Result { Ok(Config { interface: iface, peers }) } -pub fn dump_interface(conn: &Connection, config: &Config) -> Result<()> { +pub fn dump_interface(conn: &Connection, config: &Config) -> Result { let mut stmt = conn.prepare("INSERT INTO wg_interface (private_key, dns, address, listen_port, mtu) VALUES (?, ?, ?, ?, ?)")?; let cif = &config.interface; stmt.execute(params![ @@ -113,7 +113,7 @@ pub fn dump_interface(conn: &Connection, config: &Config) -> Result<()> { &peer.endpoint ])?; } - Ok(()) + Ok(interface_id) } pub fn get_connection(path: Option<&Path>) -> Result { diff --git a/burrow/src/wireguard/config.rs b/burrow/src/wireguard/config.rs index 2a9dc14..6fc4b7f 100644 --- a/burrow/src/wireguard/config.rs +++ b/burrow/src/wireguard/config.rs @@ -115,6 +115,12 @@ impl Default for Config { } } +impl Config { + pub fn from_toml(toml: &str) -> Result { + toml::from_str(toml).map_err(Into::into) + } +} + #[cfg(test)] mod tests { use super::*; From f6241e90d5a759632b761f2fb05bf8ba24ce0301 Mon Sep 17 00:00:00 2001 From: Jett Chen Date: Sun, 12 May 2024 01:07:05 +0800 Subject: [PATCH 3/6] WIP: UI for adding config --- Apple/App/App-macOS.entitlements | 2 +- Apple/App/BurrowView.swift | 32 +++++++++++++++++-- .../PacketTunnelProvider.swift | 4 +-- Apple/Shared/Client.swift | 5 +-- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/Apple/App/App-macOS.entitlements b/Apple/App/App-macOS.entitlements index 53fcbb7..e39ba66 100644 --- a/Apple/App/App-macOS.entitlements +++ b/Apple/App/App-macOS.entitlements @@ -13,7 +13,7 @@ com.apple.security.application-groups - $(APP_GROUP_IDENTIFIER) + group.com.hackclub.burrow diff --git a/Apple/App/BurrowView.swift b/Apple/App/BurrowView.swift index 8447592..ab9c558 100644 --- a/Apple/App/BurrowView.swift +++ b/Apple/App/BurrowView.swift @@ -1,10 +1,13 @@ import AuthenticationServices import SwiftUI +import BurrowShared #if !os(macOS) struct BurrowView: View { @Environment(\.webAuthenticationSession) private var webAuthenticationSession + @State private var rpcClient: Client? = nil + @State private var showAlert = false var body: some View { NavigationStack { @@ -17,6 +20,7 @@ struct BurrowView: View { Menu { Button("Hack Club", action: addHackClubNetwork) Button("WireGuard", action: addWireGuardNetwork) + Button("Custom", action: sncAddCustomnetwork) } label: { Image(systemName: "plus.circle.fill") .font(.title) @@ -34,7 +38,7 @@ struct BurrowView: View { .handleOAuth2Callback() } } - + private func addHackClubNetwork() { Task { try await authenticateWithSlack() @@ -42,7 +46,31 @@ struct BurrowView: View { } private func addWireGuardNetwork() { - + } + private func getClient() throws -> Client { + if self.rpcClient == nil { + let client = try Client() + self.rpcClient = client + } + return self.rpcClient! + } + private func sncAddCustomnetwork() { + Task { + try await addCustomnetwork() + } + } + private func addCustomnetwork() async { + do { + let networkToml = "" + let client = try getClient() + try await client.single_request("AddConfigToml", params: networkToml, type: BurrowResult.self) + alert("Successs!", isPresented: $showAlert){ + Button("OK", role: .cancel) {} + } + + } catch { + + } } private func authenticateWithSlack() async throws { diff --git a/Apple/NetworkExtension/PacketTunnelProvider.swift b/Apple/NetworkExtension/PacketTunnelProvider.swift index 89e0de6..094af50 100644 --- a/Apple/NetworkExtension/PacketTunnelProvider.swift +++ b/Apple/NetworkExtension/PacketTunnelProvider.swift @@ -41,7 +41,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { override func stopTunnel(with reason: NEProviderStopReason) async { do { let client = try Client() - _ = try await client.single_request("Stop", type: BurrowResult.self) + _ = try await client.single_request("Stop", params:nil, type: BurrowResult.self) self.logger.log("Stopped client.") } catch { self.logger.error("Failed to stop tunnel: \(error)") @@ -51,7 +51,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider { guard let client = self.client else { throw BurrowError.noClient } - let srvConfig = try await client.single_request("ServerConfig", type: BurrowResult.self) + let srvConfig = try await client.single_request("ServerConfig", params: nil, type: BurrowResult.self) guard let serverconfig = srvConfig.Ok else { throw BurrowError.resultIsError } diff --git a/Apple/Shared/Client.swift b/Apple/Shared/Client.swift index f643c6c..7d753a8 100644 --- a/Apple/Shared/Client.swift +++ b/Apple/Shared/Client.swift @@ -81,10 +81,11 @@ public final class Client { ) return try await send(req) } - public func single_request(_ request: String, type: U.Type = U.self) async throws -> U { + public func single_request(_ request: String, params: String? = nil, type: U.Type = U.self) async throws -> U { let req = BurrowSimpleRequest( id: generator.next(upperBound: UInt.max), - command: request + command: request, + params:params ) return try await send(req) } From c8a21c73a88a2485b335cf1cba9832345649d661 Mon Sep 17 00:00:00 2001 From: Jett Chen Date: Sat, 18 May 2024 22:52:52 +0800 Subject: [PATCH 4/6] updated packages --- .../xcshareddata/swiftpm/Package.resolved | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..9378372 --- /dev/null +++ b/Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,86 @@ +{ + "pins" : [ + { + "identity" : "collectionconcurrencykit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/JohnSundell/CollectionConcurrencyKit.git", + "state" : { + "revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95", + "version" : "0.2.0" + } + }, + { + "identity" : "cryptoswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/krzyzanowskim/CryptoSwift.git", + "state" : { + "revision" : "7892a123f7e8d0fe62f9f03728b17bbd4f94df5c", + "version" : "1.8.1" + } + }, + { + "identity" : "sourcekitten", + "kind" : "remoteSourceControl", + "location" : "https://github.com/jpsim/SourceKitten.git", + "state" : { + "revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56", + "version" : "0.34.1" + } + }, + { + "identity" : "swift-argument-parser", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-argument-parser.git", + "state" : { + "revision" : "8f4d2753f0e4778c76d5f05ad16c74f707390531", + "version" : "1.2.3" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax.git", + "state" : { + "revision" : "64889f0c732f210a935a0ad7cda38f77f876262d", + "version" : "509.1.1" + } + }, + { + "identity" : "swiftlint", + "kind" : "remoteSourceControl", + "location" : "https://github.com/realm/SwiftLint.git", + "state" : { + "branch" : "main", + "revision" : "7595ad3fafc1a31086dc40ba01fd898bf6b42d5f" + } + }, + { + "identity" : "swiftytexttable", + "kind" : "remoteSourceControl", + "location" : "https://github.com/scottrhoyt/SwiftyTextTable.git", + "state" : { + "revision" : "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3", + "version" : "0.9.0" + } + }, + { + "identity" : "swxmlhash", + "kind" : "remoteSourceControl", + "location" : "https://github.com/drmohundro/SWXMLHash.git", + "state" : { + "revision" : "a853604c9e9a83ad9954c7e3d2a565273982471f", + "version" : "7.0.2" + } + }, + { + "identity" : "yams", + "kind" : "remoteSourceControl", + "location" : "https://github.com/jpsim/Yams.git", + "state" : { + "revision" : "0d9ee7ea8c4ebd4a489ad7a73d5c6cad55d6fed3", + "version" : "5.0.6" + } + } + ], + "version" : 2 +} From 3ba0004370ea3d78591556df07e519c7489634c2 Mon Sep 17 00:00:00 2001 From: Jett Chen Date: Sun, 19 May 2024 00:23:34 +0800 Subject: [PATCH 5/6] Add button for sending toml --- Apple/App/App-iOS.entitlements | 2 + Apple/App/App-macOS.entitlements | 2 + Apple/App/BurrowView.swift | 2 +- Apple/App/MenuItemToggleView.swift | 56 +++++++++++++++---- Apple/App/RpcOperations.swift | 14 +++++ Apple/Burrow.xcodeproj/project.pbxproj | 4 ++ .../NetworkExtension-iOS.entitlements | 4 ++ burrow/src/wireguard/config.rs | 1 + 8 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 Apple/App/RpcOperations.swift diff --git a/Apple/App/App-iOS.entitlements b/Apple/App/App-iOS.entitlements index 53fcbb7..588ec3e 100644 --- a/Apple/App/App-iOS.entitlements +++ b/Apple/App/App-iOS.entitlements @@ -2,6 +2,8 @@ + com.apple.security.network.server + com.apple.developer.associated-domains applinks:burrow.rs?mode=developer diff --git a/Apple/App/App-macOS.entitlements b/Apple/App/App-macOS.entitlements index e39ba66..4d5db93 100644 --- a/Apple/App/App-macOS.entitlements +++ b/Apple/App/App-macOS.entitlements @@ -2,6 +2,8 @@ + com.apple.security.network.server + com.apple.developer.associated-domains applinks:burrow.rs?mode=developer diff --git a/Apple/App/BurrowView.swift b/Apple/App/BurrowView.swift index ab9c558..2c6c571 100644 --- a/Apple/App/BurrowView.swift +++ b/Apple/App/BurrowView.swift @@ -6,7 +6,7 @@ import BurrowShared struct BurrowView: View { @Environment(\.webAuthenticationSession) private var webAuthenticationSession - @State private var rpcClient: Client? = nil + @State private var rpcClient: Client? @State private var showAlert = false var body: some View { diff --git a/Apple/App/MenuItemToggleView.swift b/Apple/App/MenuItemToggleView.swift index 07db51d..c8b41f8 100644 --- a/Apple/App/MenuItemToggleView.swift +++ b/Apple/App/MenuItemToggleView.swift @@ -6,30 +6,66 @@ // import SwiftUI +import BurrowShared struct MenuItemToggleView: View { @Environment(\.tunnel) var tunnel: Tunnel + @State private var showAlert = false var body: some View { - HStack { - VStack(alignment: .leading) { - Text("Burrow") - .font(.headline) - Text(tunnel.status.description) - .font(.subheadline) - } - Spacer() - Toggle(isOn: tunnel.toggleIsOn) { - } + VStack { + HStack { + VStack(alignment: .leading) { + Text("Burrow") + .font(.headline) + Text(tunnel.status.description) + .font(.subheadline) + } + Spacer() + Toggle(isOn: tunnel.toggleIsOn) { + } .disabled(tunnel.toggleDisabled) .toggleStyle(.switch) + } + Button("Add Custom WG Config", action: sncAddCustomnetwork) } .accessibilityElement(children: .combine) .padding(.horizontal, 4) .padding(10) .frame(minWidth: 300, minHeight: 32, maxHeight: 32) } + + func sncAddCustomnetwork(){ + Task { + try await addCustomnetwork() + } + } + + func addCustomnetwork() async { + do{ + let networkToml = """ +[[peers]] +public_key = "8GaFjVO6c4luCHG4ONO+1bFG8tO+Zz5/Gy+Geht1USM=" +preshared_key = "ha7j4BjD49sIzyF9SNlbueK0AMHghlj6+u0G3bzC698=" +allowed_ips = ["8.8.8.8/32", "0.0.0.0/0"] +endpoint = "wg.burrow.rs:51820" + +[interface] +private_key = "OEPVdomeLTxTIBvv3TYsJRge0Hp9NMiY0sIrhT8OWG8=" +address = ["10.13.13.2/24"] +listen_port = 51820 +dns = [] +""" + let client = try Client() + try await client.single_request("AddConfigToml", params: networkToml, type: BurrowResult.self) + alert("Successs!", isPresented: $showAlert){ + Button("OK", role: .cancel) {} + } + } catch { + + } + } } extension Tunnel { diff --git a/Apple/App/RpcOperations.swift b/Apple/App/RpcOperations.swift new file mode 100644 index 0000000..3cd545b --- /dev/null +++ b/Apple/App/RpcOperations.swift @@ -0,0 +1,14 @@ +// +// RpcOperations.swift +// App +// +// Created by Jett Chen on 2024/5/18. +// + +import Foundation + +class RpcOperations{ + func uploadConfig(){ + + } +} diff --git a/Apple/Burrow.xcodeproj/project.pbxproj b/Apple/Burrow.xcodeproj/project.pbxproj index a3be02d..eecd67e 100644 --- a/Apple/Burrow.xcodeproj/project.pbxproj +++ b/Apple/Burrow.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 0BA6D73C2BA6393200BD4B55 /* NWConnection+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00117302B2FFFC900D87C25 /* NWConnection+Async.swift */; }; 0BA6D73D2BA6393B00BD4B55 /* NewlineProtocolFramer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00117322B3001A400D87C25 /* NewlineProtocolFramer.swift */; }; 0BA6D73E2BA6394B00BD4B55 /* DataTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B28F1552ABF463A000D44B0 /* DataTypes.swift */; }; + 0BE456612BF90752005E4D47 /* RpcOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BE456602BF90752005E4D47 /* RpcOperations.swift */; }; 43AA26D82A10004900F14CE6 /* MenuItemToggleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43AA26D72A10004900F14CE6 /* MenuItemToggleView.swift */; }; D000363D2BB8928E00E582EC /* NetworkCarouselView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D000363C2BB8928E00E582EC /* NetworkCarouselView.swift */; }; D000363F2BB895FB00E582EC /* OAuth2.swift in Sources */ = {isa = PBXBuildFile; fileRef = D000363E2BB895FB00E582EC /* OAuth2.swift */; }; @@ -79,6 +80,7 @@ /* Begin PBXFileReference section */ 0B28F1552ABF463A000D44B0 /* DataTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataTypes.swift; sourceTree = ""; }; 0B46E8DF2AC918CA00BA2A3C /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = ""; }; + 0BE456602BF90752005E4D47 /* RpcOperations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RpcOperations.swift; sourceTree = ""; }; 43AA26D72A10004900F14CE6 /* MenuItemToggleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuItemToggleView.swift; sourceTree = ""; }; D000363C2BB8928E00E582EC /* NetworkCarouselView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkCarouselView.swift; sourceTree = ""; }; D000363E2BB895FB00E582EC /* OAuth2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuth2.swift; sourceTree = ""; }; @@ -259,6 +261,7 @@ D0FAB5952B818B2900F6A84B /* TunnelButton.swift */, D0B98FC629FDC5B5004E7149 /* Tunnel.swift */, D0FAB5912B818A5900F6A84B /* NetworkExtensionTunnel.swift */, + 0BE456602BF90752005E4D47 /* RpcOperations.swift */, D0BCC5FC2A086D4700AD070D /* NetworkExtension+Async.swift */, D05EF8C72B81818D0017AB4F /* FloatingButtonStyle.swift */, D05B9F7929E39EED008CB1F9 /* Assets.xcassets */, @@ -485,6 +488,7 @@ D000363F2BB895FB00E582EC /* OAuth2.swift in Sources */, D0FAB5962B818B2900F6A84B /* TunnelButton.swift in Sources */, D00AA8972A4669BC005C8102 /* AppDelegate.swift in Sources */, + 0BE456612BF90752005E4D47 /* RpcOperations.swift in Sources */, D05EF8C82B81818D0017AB4F /* FloatingButtonStyle.swift in Sources */, D032E6522B8A79C20006B8AD /* HackClub.swift in Sources */, D05B9F7629E39EEC008CB1F9 /* BurrowApp.swift in Sources */, diff --git a/Apple/NetworkExtension/NetworkExtension-iOS.entitlements b/Apple/NetworkExtension/NetworkExtension-iOS.entitlements index 02ee960..602355e 100644 --- a/Apple/NetworkExtension/NetworkExtension-iOS.entitlements +++ b/Apple/NetworkExtension/NetworkExtension-iOS.entitlements @@ -2,6 +2,10 @@ + com.apple.security.network.server + + com.apple.security.network.client + com.apple.developer.networking.networkextension packet-tunnel-provider diff --git a/burrow/src/wireguard/config.rs b/burrow/src/wireguard/config.rs index 6fc4b7f..0fbbc7a 100644 --- a/burrow/src/wireguard/config.rs +++ b/burrow/src/wireguard/config.rs @@ -129,6 +129,7 @@ mod tests { fn tst_config_toml() { let cfig = Config::default(); let toml = toml::to_string(&cfig).unwrap(); + println!("{}", &toml); insta::assert_snapshot!(toml); let cfig2: Config = toml::from_str(&toml).unwrap(); assert_eq!(cfig, cfig2); From 59ddc36f2ce7acbb002cba04caf64462c46e5dd5 Mon Sep 17 00:00:00 2001 From: Jett Chen Date: Mon, 27 May 2024 13:58:11 +0800 Subject: [PATCH 6/6] Add support for ini parsing --- .gitignore | 4 ++ .../xcshareddata/swiftpm/Package.resolved | 14 ++-- Cargo.lock | 72 +++++++++++++++++++ burrow/Cargo.toml | 3 +- burrow/src/daemon/instance.rs | 8 +-- burrow/src/daemon/rpc/request.rs | 11 ++- burrow/src/database.rs | 47 ++++++++---- burrow/src/main.rs | 51 ++++++++++++- burrow/src/wireguard/config.rs | 62 ++++++++++++++++ burrow/src/wireguard/inifield.rs | 59 +++++++++++++++ burrow/src/wireguard/mod.rs | 1 + 11 files changed, 300 insertions(+), 32 deletions(-) create mode 100644 burrow/src/wireguard/inifield.rs diff --git a/.gitignore b/.gitignore index dc886ed..76d0818 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,7 @@ target/ .DS_STORE .idea/ + +burrow.sock +burrow.db +tmp/ diff --git a/Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 9378372..f0f02af 100644 --- a/Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Apple/Burrow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/jpsim/SourceKitten.git", "state" : { - "revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56", - "version" : "0.34.1" + "revision" : "fd4df99170f5e9d7cf9aa8312aa8506e0e7a44e7", + "version" : "0.35.0" } }, { @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-argument-parser.git", "state" : { - "revision" : "8f4d2753f0e4778c76d5f05ad16c74f707390531", - "version" : "1.2.3" + "revision" : "fee6933f37fde9a5e12a1e4aeaa93fe60116ff2a", + "version" : "1.2.2" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-syntax.git", "state" : { - "revision" : "64889f0c732f210a935a0ad7cda38f77f876262d", - "version" : "509.1.1" + "revision" : "303e5c5c36d6a558407d364878df131c3546fad8", + "version" : "510.0.2" } }, { @@ -51,7 +51,7 @@ "location" : "https://github.com/realm/SwiftLint.git", "state" : { "branch" : "main", - "revision" : "7595ad3fafc1a31086dc40ba01fd898bf6b42d5f" + "revision" : "b42f6ffe77159aed1060bf607212a0410c7623b8" } }, { diff --git a/Cargo.lock b/Cargo.lock index 03794fb..3d443f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -353,6 +353,7 @@ dependencies = [ "rand_core", "ring", "rusqlite", + "rust-ini", "schemars", "serde", "serde_json", @@ -586,6 +587,26 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -641,6 +662,12 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -699,6 +726,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + [[package]] name = "dyn-clone" version = "1.0.16" @@ -1601,6 +1637,16 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "ordered-multimap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" +dependencies = [ + "dlv-list", + "hashbrown 0.14.3", +] + [[package]] name = "overload" version = "0.1.1" @@ -1947,6 +1993,17 @@ dependencies = [ "smallvec", ] +[[package]] +name = "rust-ini" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d625ed57d8f49af6cfa514c42e1a71fadcff60eb0b1c517ff82fe41aa025b41" +dependencies = [ + "cfg-if", + "ordered-multimap", + "trim-in-place", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -2347,6 +2404,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -2627,6 +2693,12 @@ dependencies = [ "tracing-log 0.2.0", ] +[[package]] +name = "trim-in-place" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" + [[package]] name = "try-lock" version = "0.2.5" diff --git a/burrow/Cargo.toml b/burrow/Cargo.toml index d47b184..b2367fc 100644 --- a/burrow/Cargo.toml +++ b/burrow/Cargo.toml @@ -24,7 +24,7 @@ clap = { version = "4.4", features = ["derive"] } tracing = "0.1" tracing-log = "0.1" tracing-oslog = { git = "https://github.com/Stormshield-robinc/tracing-oslog" } -tracing-subscriber = { version = "0.3" , features = ["std", "env-filter"] } +tracing-subscriber = { version = "0.3", features = ["std", "env-filter"] } log = "0.4" serde = { version = "1", features = ["derive"] } serde_json = "1.0" @@ -51,6 +51,7 @@ once_cell = "1.19" console-subscriber = { version = "0.2.0", optional = true } console = "0.15.8" toml = "0.8.12" +rust-ini = "0.21.0" [dependencies.rusqlite] version = "0.31.0" diff --git a/burrow/src/daemon/instance.rs b/burrow/src/daemon/instance.rs index 018ec9f..6a5cfb0 100644 --- a/burrow/src/daemon/instance.rs +++ b/burrow/src/daemon/instance.rs @@ -17,7 +17,7 @@ use crate::{ ServerConfig, ServerInfo, }, - database::{get_connection, load_interface, dump_interface}, + database::{dump_interface, get_connection, load_interface}, wireguard::{Config, Interface}, }; @@ -116,10 +116,10 @@ impl DaemonInstance { .await?; Ok(DaemonResponseData::None) } - DaemonCommand::AddConfigToml(config_toml) => { + DaemonCommand::AddConfig(cfig_raw) => { let conn = get_connection(self.db_path.as_deref())?; - let cfig = Config::from_toml(&config_toml)?; - let _if_id = dump_interface(&conn, &cfig)?; + let cfig = Config::from_content_fmt(&cfig_raw.content, &cfig_raw.fmt)?; + let _if_id = dump_interface(&conn, &cfig, cfig_raw.interface_id)?; Ok(DaemonResponseData::None) } } diff --git a/burrow/src/daemon/rpc/request.rs b/burrow/src/daemon/rpc/request.rs index 0779abb..9e1e2e9 100644 --- a/burrow/src/daemon/rpc/request.rs +++ b/burrow/src/daemon/rpc/request.rs @@ -3,14 +3,14 @@ use serde::{Deserialize, Serialize}; use tun::TunOptions; #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] -#[serde(tag="method", content="params")] +#[serde(tag = "method", content = "params")] pub enum DaemonCommand { Start(DaemonStartOptions), ServerInfo, ServerConfig, Stop, ReloadConfig(String), - AddConfigToml(String), + AddConfig(AddConfigOptions), } #[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)] @@ -18,6 +18,13 @@ pub struct DaemonStartOptions { pub tun: TunOptions, } +#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)] +pub struct AddConfigOptions { + pub content: String, + pub fmt: String, + pub interface_id: Option, +} + #[derive(Clone, Serialize, Deserialize)] pub struct DaemonRequest { pub id: u64, diff --git a/burrow/src/database.rs b/burrow/src/database.rs index 0dbf397..4d1d38e 100644 --- a/burrow/src/database.rs +++ b/burrow/src/database.rs @@ -92,17 +92,36 @@ pub fn load_interface(conn: &Connection, interface_id: &str) -> Result { Ok(Config { interface: iface, peers }) } -pub fn dump_interface(conn: &Connection, config: &Config) -> Result { - let mut stmt = conn.prepare("INSERT INTO wg_interface (private_key, dns, address, listen_port, mtu) VALUES (?, ?, ?, ?, ?)")?; - let cif = &config.interface; - stmt.execute(params![ - cif.private_key, - to_lst(&cif.dns), - to_lst(&cif.address), - cif.listen_port, - cif.mtu - ])?; - let interface_id = conn.last_insert_rowid(); +pub fn dump_interface( + conn: &Connection, + config: &Config, + interface_id: Option, +) -> Result { + let interface_id = if let Some(id) = interface_id { + let mut stmt = conn.prepare("INSERT INTO wg_interface (private_key, dns, address, listen_port, mtu, id) VALUES (?, ?, ?, ?, ?, ?)")?; + let cif = &config.interface; + stmt.execute(params![ + cif.private_key, + to_lst(&cif.dns), + to_lst(&cif.address), + cif.listen_port, + cif.mtu, + id + ])?; + id + } else { + let mut stmt = conn.prepare("INSERT INTO wg_interface (private_key, dns, address, listen_port, mtu) VALUES (?, ?, ?, ?, ?)")?; + let cif = &config.interface; + stmt.execute(params![ + cif.private_key, + to_lst(&cif.dns), + to_lst(&cif.address), + cif.listen_port, + cif.mtu + ])?; + conn.last_insert_rowid() + }; + let mut stmt = conn.prepare("INSERT INTO wg_peer (interface_id, public_key, preshared_key, allowed_ips, endpoint) VALUES (?, ?, ?, ?, ?)")?; for peer in &config.peers { stmt.execute(params![ @@ -121,7 +140,7 @@ pub fn get_connection(path: Option<&Path>) -> Result { if !p.exists() { let conn = Connection::open(p)?; initialize_tables(&conn)?; - dump_interface(&conn, &Config::default())?; + dump_interface(&conn, &Config::default(), None)?; return Ok(conn); } Ok(Connection::open(p)?) @@ -129,8 +148,6 @@ pub fn get_connection(path: Option<&Path>) -> Result { #[cfg(test)] mod tests { - use std::path::Path; - use super::*; #[test] @@ -138,7 +155,7 @@ mod tests { let conn = Connection::open_in_memory().unwrap(); initialize_tables(&conn).unwrap(); let config = Config::default(); - dump_interface(&conn, &config).unwrap(); + dump_interface(&conn, &config, None).unwrap(); let loaded = load_interface(&conn, "1").unwrap(); assert_eq!(config, loaded); } diff --git a/burrow/src/main.rs b/burrow/src/main.rs index 295373a..93ede99 100644 --- a/burrow/src/main.rs +++ b/burrow/src/main.rs @@ -1,6 +1,10 @@ +use std::{borrow::Cow, path::PathBuf}; + use anyhow::Result; use clap::{Args, Parser, Subcommand}; +use crate::daemon::rpc::request::AddConfigOptions; + #[cfg(any(target_os = "linux", target_vendor = "apple"))] mod daemon; pub(crate) mod tracing; @@ -47,6 +51,16 @@ enum Commands { ServerConfig, /// Reload Config ReloadConfig(ReloadConfigArgs), + /// Add Server Config + AddConfig(AddServerConfigArgs), +} + +#[derive(Args)] +struct AddServerConfigArgs { + #[clap(short, long)] + path: PathBuf, + #[clap(short, long)] + interface_id: Option, } #[derive(Args)] @@ -59,7 +73,12 @@ struct ReloadConfigArgs { struct StartArgs {} #[derive(Args)] -struct DaemonArgs {} +struct DaemonArgs { + #[clap(long, short)] + socket_path: Option, + #[clap(long, short)] + db_path: Option, +} #[cfg(any(target_os = "linux", target_vendor = "apple"))] async fn try_start() -> Result<()> { @@ -132,6 +151,24 @@ async fn try_reloadconfig(interface_id: String) -> Result<()> { Ok(()) } +#[cfg(any(target_os = "linux", target_vendor = "apple"))] +async fn try_add_server_config(path: &PathBuf, interface_id: Option) -> Result<()> { + let mut client = DaemonClient::new().await?; + let ext = path + .extension() + .map(|e| e.to_string_lossy()) + .unwrap_or_else(|| Cow::Borrowed("toml")); + let content = std::fs::read_to_string(path)?; + let res = client + .send_command(DaemonCommand::AddConfig(AddConfigOptions { + content, + fmt: ext.to_string(), + interface_id, + })) + .await?; + Ok(()) +} + #[cfg(any(target_os = "linux", target_vendor = "apple"))] #[tokio::main(flavor = "current_thread")] async fn main() -> Result<()> { @@ -139,12 +176,20 @@ async fn main() -> Result<()> { let cli = Cli::parse(); match &cli.command { - Commands::Start(..) => try_start().await?, + Commands::Start(_) => try_start().await?, Commands::Stop => try_stop().await?, - Commands::Daemon(_) => daemon::daemon_main(None, None, None).await?, + Commands::Daemon(daemon_args) => { + daemon::daemon_main( + daemon_args.socket_path.as_ref().map(|p| p.as_path()), + daemon_args.db_path.as_ref().map(|p| p.as_path()), + None, + ) + .await? + } Commands::ServerInfo => try_serverinfo().await?, Commands::ServerConfig => try_serverconfig().await?, Commands::ReloadConfig(args) => try_reloadconfig(args.interface_id.clone()).await?, + Commands::AddConfig(args) => try_add_server_config(&args.path, args.interface_id).await?, } Ok(()) diff --git a/burrow/src/wireguard/config.rs b/burrow/src/wireguard/config.rs index 0fbbc7a..1d9315a 100644 --- a/burrow/src/wireguard/config.rs +++ b/burrow/src/wireguard/config.rs @@ -3,10 +3,12 @@ use std::{net::ToSocketAddrs, str::FromStr}; use anyhow::{anyhow, Error, Result}; use base64::{engine::general_purpose, Engine}; use fehler::throws; +use ini::{Ini, Properties}; use ip_network::IpNetwork; use serde::{Deserialize, Serialize}; use x25519_dalek::{PublicKey, StaticSecret}; +use super::inifield::IniField; use crate::wireguard::{Interface as WgInterface, Peer as WgPeer}; #[throws] @@ -53,6 +55,7 @@ pub struct Interface { #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct Config { + #[serde(rename = "Peer")] pub peers: Vec, pub interface: Interface, // Support for multiple interfaces? } @@ -115,10 +118,69 @@ impl Default for Config { } } +fn props_get(props: &Properties, key: &str) -> T +where + T: From, +{ + IniField::from(props.get(key)).into() +} + +impl TryFrom<&Properties> for Interface { + type Error = anyhow::Error; + + fn try_from(props: &Properties) -> Result { + Ok(Self { + private_key: props_get(props, "PrivateKey"), + address: props_get(props, "Address"), + listen_port: props_get(props, "ListenPort"), + dns: props_get(props, "DNS"), + mtu: props_get(props, "MTU"), + }) + } +} + +impl TryFrom<&Properties> for Peer { + type Error = anyhow::Error; + + fn try_from(props: &Properties) -> Result { + Ok(Self { + public_key: props_get(props, "PublicKey"), + preshared_key: props_get(props, "PresharedKey"), + allowed_ips: props_get(props, "AllowedIPs"), + endpoint: props_get(props, "Endpoint"), + persistent_keepalive: props_get(props, "PersistentKeepalive"), + name: props_get(props, "Name"), + }) + } +} + impl Config { pub fn from_toml(toml: &str) -> Result { toml::from_str(toml).map_err(Into::into) } + + pub fn from_ini(ini: &str) -> Result { + let ini = Ini::load_from_str(ini)?; + let interface = ini + .section(Some("Interface")) + .ok_or(anyhow!("Interface section not found"))?; + let peers = ini.section_all(Some("Peer")); + Ok(Self { + interface: Interface::try_from(interface)?, + peers: peers + .into_iter() + .map(|v| Peer::try_from(v)) + .collect::>>()?, + }) + } + + pub fn from_content_fmt(content: &str, fmt: &str) -> Result { + match fmt { + "toml" => Self::from_toml(content), + "ini" | "conf" => Self::from_ini(content), + _ => Err(anyhow::anyhow!("Unsupported format: {}", fmt)), + } + } } #[cfg(test)] diff --git a/burrow/src/wireguard/inifield.rs b/burrow/src/wireguard/inifield.rs new file mode 100644 index 0000000..fb65a20 --- /dev/null +++ b/burrow/src/wireguard/inifield.rs @@ -0,0 +1,59 @@ +use std::str::FromStr; + +pub struct IniField(String); + +impl FromStr for IniField { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + Ok(Self(s.to_string())) + } +} + +impl From for Vec { + fn from(field: IniField) -> Self { + field.0.split(",").map(|s| s.to_string()).collect() + } +} + +impl From for u32 { + fn from(value: IniField) -> Self { + value.0.parse().unwrap() + } +} + +impl From for Option { + fn from(value: IniField) -> Self { + Some(value.0.parse().unwrap()) + } +} + +impl From for String { + fn from(value: IniField) -> Self { + value.0 + } +} + +impl From for Option { + fn from(value: IniField) -> Self { + Some(value.0) + } +} + +impl From> for IniField +where + T: ToString, +{ + fn from(value: Option) -> Self { + match value { + Some(v) => Self(v.to_string()), + None => Self("".to_string()), + } + } +} + +impl IniField { + fn new(value: &str) -> Self { + Self(value.to_string()) + } +} diff --git a/burrow/src/wireguard/mod.rs b/burrow/src/wireguard/mod.rs index 4c70a7f..cfb4585 100755 --- a/burrow/src/wireguard/mod.rs +++ b/burrow/src/wireguard/mod.rs @@ -1,5 +1,6 @@ pub mod config; mod iface; +mod inifield; mod noise; mod pcb; mod peer;