Compare commits
6 commits
abf1101484
...
59ddc36f2c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59ddc36f2c | ||
|
|
3ba0004370 | ||
|
|
c8a21c73a8 | ||
|
|
f6241e90d5 | ||
|
|
dd3f5d0d92 | ||
|
|
ae8ea8ae54 |
21 changed files with 507 additions and 49 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -6,3 +6,7 @@ target/
|
|||
|
||||
.DS_STORE
|
||||
.idea/
|
||||
|
||||
burrow.sock
|
||||
burrow.db
|
||||
tmp/
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.associated-domains</key>
|
||||
<array>
|
||||
<string>applinks:burrow.rs?mode=developer</string>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.associated-domains</key>
|
||||
<array>
|
||||
<string>applinks:burrow.rs?mode=developer</string>
|
||||
|
|
@ -13,7 +15,7 @@
|
|||
</array>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>$(APP_GROUP_IDENTIFIER)</string>
|
||||
<string>group.com.hackclub.burrow</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
@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)
|
||||
|
|
@ -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<AnyResponseData>.self)
|
||||
alert("Successs!", isPresented: $showAlert){
|
||||
Button("OK", role: .cancel) {}
|
||||
}
|
||||
|
||||
} catch {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private func authenticateWithSlack() async throws {
|
||||
|
|
|
|||
|
|
@ -6,12 +6,15 @@
|
|||
//
|
||||
|
||||
import SwiftUI
|
||||
import BurrowShared
|
||||
|
||||
struct MenuItemToggleView: View {
|
||||
@Environment(\.tunnel)
|
||||
var tunnel: Tunnel
|
||||
@State private var showAlert = false
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
HStack {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Burrow")
|
||||
|
|
@ -25,11 +28,44 @@ struct MenuItemToggleView: View {
|
|||
.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<AnyResponseData>.self)
|
||||
alert("Successs!", isPresented: $showAlert){
|
||||
Button("OK", role: .cancel) {}
|
||||
}
|
||||
} catch {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Tunnel {
|
||||
|
|
|
|||
14
Apple/App/RpcOperations.swift
Normal file
14
Apple/App/RpcOperations.swift
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// RpcOperations.swift
|
||||
// App
|
||||
//
|
||||
// Created by Jett Chen on 2024/5/18.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class RpcOperations{
|
||||
func uploadConfig(){
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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 = "<group>"; };
|
||||
0B46E8DF2AC918CA00BA2A3C /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = "<group>"; };
|
||||
0BE456602BF90752005E4D47 /* RpcOperations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RpcOperations.swift; sourceTree = "<group>"; };
|
||||
43AA26D72A10004900F14CE6 /* MenuItemToggleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuItemToggleView.swift; sourceTree = "<group>"; };
|
||||
D000363C2BB8928E00E582EC /* NetworkCarouselView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkCarouselView.swift; sourceTree = "<group>"; };
|
||||
D000363E2BB895FB00E582EC /* OAuth2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuth2.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -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 */,
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>packet-tunnel-provider</string>
|
||||
|
|
|
|||
|
|
@ -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<AnyResponseData>.self)
|
||||
_ = try await client.single_request("Stop", params:nil, type: BurrowResult<AnyResponseData>.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<ServerConfig>.self)
|
||||
let srvConfig = try await client.single_request("ServerConfig", params: nil, type: BurrowResult<ServerConfig>.self)
|
||||
guard let serverconfig = srvConfig.Ok else {
|
||||
throw BurrowError.resultIsError
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,10 +81,11 @@ public final class Client {
|
|||
)
|
||||
return try await send(req)
|
||||
}
|
||||
public func single_request<U: Decodable>(_ request: String, type: U.Type = U.self) async throws -> U {
|
||||
public func single_request<U: Decodable>(_ 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)
|
||||
}
|
||||
|
|
|
|||
125
Cargo.lock
generated
125
Cargo.lock
generated
|
|
@ -353,10 +353,12 @@ dependencies = [
|
|||
"rand_core",
|
||||
"ring",
|
||||
"rusqlite",
|
||||
"rust-ini",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"toml",
|
||||
"tracing",
|
||||
"tracing-journald",
|
||||
"tracing-log 0.1.4",
|
||||
|
|
@ -585,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"
|
||||
|
|
@ -640,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"
|
||||
|
|
@ -698,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"
|
||||
|
|
@ -1600,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"
|
||||
|
|
@ -1946,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"
|
||||
|
|
@ -2102,6 +2160,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"
|
||||
|
|
@ -2337,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"
|
||||
|
|
@ -2426,6 +2502,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"
|
||||
|
|
@ -2583,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"
|
||||
|
|
@ -2981,6 +3097,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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -50,6 +50,8 @@ futures = "0.3.28"
|
|||
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"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use crate::{
|
|||
ServerConfig,
|
||||
ServerInfo,
|
||||
},
|
||||
database::{get_connection, load_interface},
|
||||
database::{dump_interface, get_connection, load_interface},
|
||||
wireguard::{Config, Interface},
|
||||
};
|
||||
|
||||
|
|
@ -116,6 +116,12 @@ impl DaemonInstance {
|
|||
.await?;
|
||||
Ok(DaemonResponseData::None)
|
||||
}
|
||||
DaemonCommand::AddConfig(cfig_raw) => {
|
||||
let conn = get_connection(self.db_path.as_deref())?;
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,13 +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),
|
||||
AddConfig(AddConfigOptions),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
|
|
@ -17,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<i64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct DaemonRequest {
|
||||
pub id: u64,
|
||||
|
|
|
|||
|
|
@ -92,7 +92,24 @@ pub fn load_interface(conn: &Connection, interface_id: &str) -> Result<Config> {
|
|||
Ok(Config { interface: iface, peers })
|
||||
}
|
||||
|
||||
pub fn dump_interface(conn: &Connection, config: &Config) -> Result<()> {
|
||||
pub fn dump_interface(
|
||||
conn: &Connection,
|
||||
config: &Config,
|
||||
interface_id: Option<i64>,
|
||||
) -> Result<i64> {
|
||||
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![
|
||||
|
|
@ -102,7 +119,9 @@ pub fn dump_interface(conn: &Connection, config: &Config) -> Result<()> {
|
|||
cif.listen_port,
|
||||
cif.mtu
|
||||
])?;
|
||||
let interface_id = conn.last_insert_rowid();
|
||||
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![
|
||||
|
|
@ -113,7 +132,7 @@ pub fn dump_interface(conn: &Connection, config: &Config) -> Result<()> {
|
|||
&peer.endpoint
|
||||
])?;
|
||||
}
|
||||
Ok(())
|
||||
Ok(interface_id)
|
||||
}
|
||||
|
||||
pub fn get_connection(path: Option<&Path>) -> Result<Connection> {
|
||||
|
|
@ -121,7 +140,7 @@ pub fn get_connection(path: Option<&Path>) -> Result<Connection> {
|
|||
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<Connection> {
|
|||
|
||||
#[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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<i64>,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
|
|
@ -59,7 +73,12 @@ struct ReloadConfigArgs {
|
|||
struct StartArgs {}
|
||||
|
||||
#[derive(Args)]
|
||||
struct DaemonArgs {}
|
||||
struct DaemonArgs {
|
||||
#[clap(long, short)]
|
||||
socket_path: Option<PathBuf>,
|
||||
#[clap(long, short)]
|
||||
db_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[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<i64>) -> 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(())
|
||||
|
|
|
|||
|
|
@ -3,9 +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]
|
||||
|
|
@ -31,7 +34,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<String>,
|
||||
|
|
@ -41,7 +44,7 @@ pub struct Peer {
|
|||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Interface {
|
||||
pub private_key: String,
|
||||
pub address: Vec<String>,
|
||||
|
|
@ -50,8 +53,9 @@ pub struct Interface {
|
|||
pub mtu: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
#[serde(rename = "Peer")]
|
||||
pub peers: Vec<Peer>,
|
||||
pub interface: Interface, // Support for multiple interfaces?
|
||||
}
|
||||
|
|
@ -113,3 +117,83 @@ impl Default for Config {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn props_get<T>(props: &Properties, key: &str) -> T
|
||||
where
|
||||
T: From<IniField>,
|
||||
{
|
||||
IniField::from(props.get(key)).into()
|
||||
}
|
||||
|
||||
impl TryFrom<&Properties> for Interface {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(props: &Properties) -> Result<Self, Error> {
|
||||
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<Self, Error> {
|
||||
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<Self> {
|
||||
toml::from_str(toml).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub fn from_ini(ini: &str) -> Result<Self> {
|
||||
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::<Result<Vec<Peer>>>()?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_content_fmt(content: &str, fmt: &str) -> Result<Self> {
|
||||
match fmt {
|
||||
"toml" => Self::from_toml(content),
|
||||
"ini" | "conf" => Self::from_ini(content),
|
||||
_ => Err(anyhow::anyhow!("Unsupported format: {}", fmt)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
59
burrow/src/wireguard/inifield.rs
Normal file
59
burrow/src/wireguard/inifield.rs
Normal file
|
|
@ -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<Self, Self::Err> {
|
||||
Ok(Self(s.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IniField> for Vec<String> {
|
||||
fn from(field: IniField) -> Self {
|
||||
field.0.split(",").map(|s| s.to_string()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IniField> for u32 {
|
||||
fn from(value: IniField) -> Self {
|
||||
value.0.parse().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IniField> for Option<u32> {
|
||||
fn from(value: IniField) -> Self {
|
||||
Some(value.0.parse().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IniField> for String {
|
||||
fn from(value: IniField) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IniField> for Option<String> {
|
||||
fn from(value: IniField) -> Self {
|
||||
Some(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Option<T>> for IniField
|
||||
where
|
||||
T: ToString,
|
||||
{
|
||||
fn from(value: Option<T>) -> Self {
|
||||
match value {
|
||||
Some(v) => Self(v.to_string()),
|
||||
None => Self("".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IniField {
|
||||
fn new(value: &str) -> Self {
|
||||
Self(value.to_string())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
pub mod config;
|
||||
mod iface;
|
||||
mod inifield;
|
||||
mod noise;
|
||||
mod pcb;
|
||||
mod peer;
|
||||
|
|
|
|||
|
|
@ -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 = []
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue