Merge branch 'main' into ios-ui
This commit is contained in:
commit
1651872939
31 changed files with 900 additions and 117 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -3,3 +3,6 @@ xcuserdata
|
||||||
|
|
||||||
# Rust
|
# Rust
|
||||||
target/
|
target/
|
||||||
|
|
||||||
|
.DS_STORE
|
||||||
|
.idea/
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
0B28F1562ABF463A000D44B0 /* DataTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B28F1552ABF463A000D44B0 /* DataTypes.swift */; };
|
||||||
|
0B46E8E02AC918CA00BA2A3C /* BurrowIpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B46E8DF2AC918CA00BA2A3C /* BurrowIpc.swift */; };
|
||||||
43AA26D82A10004900F14CE6 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43AA26D72A10004900F14CE6 /* MenuView.swift */; };
|
43AA26D82A10004900F14CE6 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43AA26D72A10004900F14CE6 /* MenuView.swift */; };
|
||||||
D00AA8972A4669BC005C8102 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00AA8962A4669BC005C8102 /* AppDelegate.swift */; };
|
D00AA8972A4669BC005C8102 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00AA8962A4669BC005C8102 /* AppDelegate.swift */; };
|
||||||
D020F65829E4A697002790F6 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020F65729E4A697002790F6 /* PacketTunnelProvider.swift */; };
|
D020F65829E4A697002790F6 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020F65729E4A697002790F6 /* PacketTunnelProvider.swift */; };
|
||||||
|
|
@ -46,6 +48,8 @@
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
0B28F1552ABF463A000D44B0 /* DataTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataTypes.swift; sourceTree = "<group>"; };
|
||||||
|
0B46E8DF2AC918CA00BA2A3C /* BurrowIpc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BurrowIpc.swift; sourceTree = "<group>"; };
|
||||||
43AA26D72A10004900F14CE6 /* MenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuView.swift; sourceTree = "<group>"; };
|
43AA26D72A10004900F14CE6 /* MenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuView.swift; sourceTree = "<group>"; };
|
||||||
D00AA8962A4669BC005C8102 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
D00AA8962A4669BC005C8102 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
D020F63D29E4A1FF002790F6 /* Identity.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Identity.xcconfig; sourceTree = "<group>"; };
|
D020F63D29E4A1FF002790F6 /* Identity.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Identity.xcconfig; sourceTree = "<group>"; };
|
||||||
|
|
@ -122,6 +126,8 @@
|
||||||
D020F66729E4A95D002790F6 /* NetworkExtension-iOS.entitlements */,
|
D020F66729E4A95D002790F6 /* NetworkExtension-iOS.entitlements */,
|
||||||
D020F66629E4A95D002790F6 /* NetworkExtension-macOS.entitlements */,
|
D020F66629E4A95D002790F6 /* NetworkExtension-macOS.entitlements */,
|
||||||
D020F66229E4A6E5002790F6 /* NetworkExtension.xcconfig */,
|
D020F66229E4A6E5002790F6 /* NetworkExtension.xcconfig */,
|
||||||
|
0B28F1552ABF463A000D44B0 /* DataTypes.swift */,
|
||||||
|
0B46E8DF2AC918CA00BA2A3C /* BurrowIpc.swift */,
|
||||||
D0B98FD729FDDB57004E7149 /* libburrow */,
|
D0B98FD729FDDB57004E7149 /* libburrow */,
|
||||||
);
|
);
|
||||||
path = NetworkExtension;
|
path = NetworkExtension;
|
||||||
|
|
@ -304,6 +310,8 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
0B28F1562ABF463A000D44B0 /* DataTypes.swift in Sources */,
|
||||||
|
0B46E8E02AC918CA00BA2A3C /* BurrowIpc.swift in Sources */,
|
||||||
D020F65829E4A697002790F6 /* PacketTunnelProvider.swift in Sources */,
|
D020F65829E4A697002790F6 /* PacketTunnelProvider.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|
|
||||||
133
Apple/NetworkExtension/BurrowIpc.swift
Normal file
133
Apple/NetworkExtension/BurrowIpc.swift
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
import Foundation
|
||||||
|
import Network
|
||||||
|
import os
|
||||||
|
|
||||||
|
final class LineProtocol: NWProtocolFramerImplementation {
|
||||||
|
static let definition = NWProtocolFramer.Definition(implementation: LineProtocol.self)
|
||||||
|
static let label = "Lines"
|
||||||
|
init(framer: NWProtocolFramer.Instance) { }
|
||||||
|
func start(framer: NWProtocolFramer.Instance) -> NWProtocolFramer.StartResult { .ready }
|
||||||
|
func stop(framer: NWProtocolFramer.Instance) -> Bool { true }
|
||||||
|
func wakeup(framer: NWProtocolFramer.Instance) { }
|
||||||
|
func cleanup(framer: NWProtocolFramer.Instance) { }
|
||||||
|
func lines(from buffer: UnsafeMutableRawBufferPointer?) -> (lines: [Data], size: Int)? {
|
||||||
|
guard let buffer = buffer else { return nil }
|
||||||
|
let lines = buffer
|
||||||
|
.split(separator: 10)
|
||||||
|
guard !lines.isEmpty else { return nil }
|
||||||
|
let size = lines
|
||||||
|
.lazy
|
||||||
|
.map(\.count)
|
||||||
|
.reduce(0, +) + lines.count
|
||||||
|
let strings = lines
|
||||||
|
.lazy
|
||||||
|
.map { Data($0) }
|
||||||
|
return (lines: Array(strings), size: size)
|
||||||
|
}
|
||||||
|
func handleInput(framer: NWProtocolFramer.Instance) -> Int {
|
||||||
|
var result: [Data] = []
|
||||||
|
_ = framer.parseInput(minimumIncompleteLength: 1, maximumLength: 16_000) { buffer, _ in
|
||||||
|
guard let (lines, size) = lines(from: buffer) else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
result = lines
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
for line in result {
|
||||||
|
framer.deliverInput(data: line, message: .init(instance: framer), isComplete: true)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
func handleOutput(
|
||||||
|
framer: NWProtocolFramer.Instance,
|
||||||
|
message: NWProtocolFramer.Message,
|
||||||
|
messageLength: Int,
|
||||||
|
isComplete: Bool
|
||||||
|
) {
|
||||||
|
do {
|
||||||
|
try framer.writeOutputNoCopy(length: messageLength)
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension NWConnection {
|
||||||
|
func receiveMessage() async throws -> (Data?, NWConnection.ContentContext?, Bool) {
|
||||||
|
try await withUnsafeThrowingContinuation { continuation in
|
||||||
|
receiveMessage { completeContent, contentContext, isComplete, error in
|
||||||
|
if let error = error {
|
||||||
|
continuation.resume(throwing: error)
|
||||||
|
}
|
||||||
|
continuation.resume(returning: (completeContent, contentContext, isComplete))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func send_raw(_ request: Data) async throws -> Data {
|
||||||
|
try await withCheckedThrowingContinuation { continuation in
|
||||||
|
let comp: NWConnection.SendCompletion = .contentProcessed {error in
|
||||||
|
if let error = error {
|
||||||
|
continuation.resume(with: .failure(error))
|
||||||
|
} else {
|
||||||
|
continuation.resume(with: .success(request))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.send(content: request, completion: comp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class BurrowIpc {
|
||||||
|
let connection: NWConnection
|
||||||
|
private var generator = SystemRandomNumberGenerator()
|
||||||
|
private var logger: Logger
|
||||||
|
init(logger: Logger) {
|
||||||
|
let params = NWParameters.tcp
|
||||||
|
params.defaultProtocolStack
|
||||||
|
.applicationProtocols
|
||||||
|
.insert(NWProtocolFramer.Options(definition: LineProtocol.definition), at: 0)
|
||||||
|
let connection = NWConnection(to: .unix(path: "burrow.sock"), using: params)
|
||||||
|
connection.start(queue: .global())
|
||||||
|
self.connection = connection
|
||||||
|
self.logger = logger
|
||||||
|
}
|
||||||
|
func send<T: Request, U: Decodable>(_ request: T) async throws -> U {
|
||||||
|
do {
|
||||||
|
let id: UInt = generator.next(upperBound: UInt.max)
|
||||||
|
var copy = request
|
||||||
|
copy.id = id
|
||||||
|
var data = try JSONEncoder().encode(request)
|
||||||
|
data.append(contentsOf: [10])
|
||||||
|
_ = try await self.connection.send_raw(data)
|
||||||
|
return try JSONDecoder().decode(Response<U>.self, from: data).result
|
||||||
|
} catch {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func receive_raw() async throws -> Data {
|
||||||
|
let (completeContent, _, _) = try await connection.receiveMessage()
|
||||||
|
self.logger.info("Received raw message response")
|
||||||
|
guard let data = completeContent else {
|
||||||
|
throw BurrowError.resultIsNone
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func request<U: Decodable>(_ request: Request, type: U.Type) async throws -> U {
|
||||||
|
do {
|
||||||
|
var data: Data = try JSONEncoder().encode(request)
|
||||||
|
data.append(contentsOf: [10])
|
||||||
|
_ = try await self.connection.send_raw(data)
|
||||||
|
self.logger.debug("message sent")
|
||||||
|
let receivedData = try await receive_raw()
|
||||||
|
self.logger.info("Received result: \(String(decoding: receivedData, as: UTF8.self))")
|
||||||
|
return try self.parse_response(receivedData)
|
||||||
|
} catch {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parse_response<U: Decodable>(_ response: Data) throws -> U {
|
||||||
|
try JSONDecoder().decode(U.self, from: response)
|
||||||
|
}
|
||||||
|
}
|
||||||
40
Apple/NetworkExtension/DataTypes.swift
Normal file
40
Apple/NetworkExtension/DataTypes.swift
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum BurrowError: Error {
|
||||||
|
case addrDoesntExist
|
||||||
|
case resultIsError
|
||||||
|
case cantParseResult
|
||||||
|
case resultIsNone
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol Request: Codable {
|
||||||
|
var id: UInt { get set }
|
||||||
|
var command: String { get set }
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BurrowRequest: Request {
|
||||||
|
var id: UInt
|
||||||
|
var command: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Response<T>: Decodable where T: Decodable {
|
||||||
|
var id: UInt
|
||||||
|
var result: T
|
||||||
|
}
|
||||||
|
|
||||||
|
// swiftlint:disable identifier_name
|
||||||
|
struct BurrowResult<T>: Codable where T: Codable {
|
||||||
|
var Ok: T?
|
||||||
|
var Err: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ServerConfigData: Codable {
|
||||||
|
struct InternalConfig: Codable {
|
||||||
|
let address: String?
|
||||||
|
let name: String?
|
||||||
|
let mtu: Int32?
|
||||||
|
}
|
||||||
|
let ServerConfig: InternalConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// swiftlint:enable identifier_name
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>com.apple.security.network.client</key>
|
||||||
|
<true/>
|
||||||
<key>com.apple.developer.networking.networkextension</key>
|
<key>com.apple.developer.networking.networkextension</key>
|
||||||
<array>
|
<array>
|
||||||
<string>packet-tunnel-provider</string>
|
<string>packet-tunnel-provider</string>
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,66 @@
|
||||||
import libburrow
|
import libburrow
|
||||||
import NetworkExtension
|
import NetworkExtension
|
||||||
import OSLog
|
import os
|
||||||
|
|
||||||
class PacketTunnelProvider: NEPacketTunnelProvider {
|
class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||||
let logger = Logger(subsystem: "com.hackclub.burrow", category: "General")
|
let logger = Logger(subsystem: "com.hackclub.burrow", category: "frontend")
|
||||||
|
var client: BurrowIpc?
|
||||||
|
var osInitialized = false
|
||||||
override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
|
override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
|
||||||
let fild = libburrow.retrieve()
|
logger.log("Starting tunnel")
|
||||||
if fild == -1 {
|
if !osInitialized {
|
||||||
// Not sure if this is the right way to return an error
|
libburrow.initialize_oslog()
|
||||||
logger.error("Failed to retrieve file descriptor for burrow.")
|
osInitialized = true
|
||||||
let err = NSError(
|
|
||||||
domain: "com.hackclub.burrow",
|
|
||||||
code: 1_010,
|
|
||||||
userInfo: [NSLocalizedDescriptionKey: "Failed to find TunInterface"]
|
|
||||||
)
|
|
||||||
completionHandler(err)
|
|
||||||
}
|
}
|
||||||
logger.info("fd: \(fild)")
|
libburrow.start_srv()
|
||||||
|
client = BurrowIpc(logger: logger)
|
||||||
|
logger.info("Started server")
|
||||||
|
Task {
|
||||||
|
do {
|
||||||
|
let command = BurrowRequest(id: 0, command: "ServerConfig")
|
||||||
|
guard let data = try await client?.request(command, type: Response<BurrowResult<ServerConfigData>>.self)
|
||||||
|
else {
|
||||||
|
throw BurrowError.cantParseResult
|
||||||
|
}
|
||||||
|
let encoded = try JSONEncoder().encode(data.result)
|
||||||
|
self.logger.log("Received final data: \(String(decoding: encoded, as: UTF8.self))")
|
||||||
|
guard let serverconfig = data.result.Ok else {
|
||||||
|
throw BurrowError.resultIsError
|
||||||
|
}
|
||||||
|
guard let tunNs = self.generateTunSettings(from: serverconfig) else {
|
||||||
|
throw BurrowError.addrDoesntExist
|
||||||
|
}
|
||||||
|
try await self.setTunnelNetworkSettings(tunNs)
|
||||||
|
self.logger.info("Set remote tunnel address to \(tunNs.tunnelRemoteAddress)")
|
||||||
completionHandler(nil)
|
completionHandler(nil)
|
||||||
|
} catch {
|
||||||
|
self.logger.error("An error occurred: \(error)")
|
||||||
|
completionHandler(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private func generateTunSettings(from: ServerConfigData) -> NETunnelNetworkSettings? {
|
||||||
|
let cfig = from.ServerConfig
|
||||||
|
guard let addr = cfig.address else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Using a makeshift remote tunnel address
|
||||||
|
let nst = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "1.1.1.1")
|
||||||
|
nst.ipv4Settings = NEIPv4Settings(addresses: [addr], subnetMasks: ["255.255.255.0"])
|
||||||
|
logger.log("Initialized ipv4 settings: \(nst.ipv4Settings)")
|
||||||
|
return nst
|
||||||
}
|
}
|
||||||
|
|
||||||
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
|
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
|
||||||
completionHandler()
|
completionHandler()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
|
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
|
||||||
if let handler = completionHandler {
|
if let handler = completionHandler {
|
||||||
handler(messageData)
|
handler(messageData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func sleep(completionHandler: @escaping () -> Void) {
|
override func sleep(completionHandler: @escaping () -> Void) {
|
||||||
completionHandler()
|
completionHandler()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func wake() {
|
override func wake() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
int retrieve();
|
void start_srv();
|
||||||
|
void initialize_oslog();
|
||||||
|
|
|
||||||
217
Cargo.lock
generated
217
Cargo.lock
generated
|
|
@ -39,16 +39,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.3.2"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
|
checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"anstyle-parse",
|
"anstyle-parse",
|
||||||
"anstyle-query",
|
"anstyle-query",
|
||||||
"anstyle-wincon",
|
"anstyle-wincon",
|
||||||
"colorchoice",
|
"colorchoice",
|
||||||
"is-terminal",
|
|
||||||
"utf8parse",
|
"utf8parse",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -78,9 +77,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-wincon"
|
name = "anstyle-wincon"
|
||||||
version = "1.0.1"
|
version = "2.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
|
checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
|
|
@ -92,6 +91,17 @@ version = "1.0.71"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-channel"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
|
||||||
|
dependencies = [
|
||||||
|
"concurrent-queue",
|
||||||
|
"event-listener",
|
||||||
|
"futures-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
@ -202,12 +212,15 @@ name = "burrow"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"async-channel",
|
||||||
"caps",
|
"caps",
|
||||||
"clap",
|
"clap",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
"insta",
|
||||||
"libsystemd",
|
"libsystemd",
|
||||||
"log",
|
"log",
|
||||||
"nix",
|
"nix",
|
||||||
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|
@ -309,20 +322,19 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.3.10"
|
version = "4.4.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a"
|
checksum = "b1d7b8d5ec32af0fadc644bf1fd509a688c2103b185644bb1e29d164e0703136"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
"once_cell",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.3.10"
|
version = "4.4.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d"
|
checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
|
|
@ -332,9 +344,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.3.2"
|
version = "4.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f"
|
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
|
@ -354,6 +366,27 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "concurrent-queue"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "console"
|
||||||
|
version = "0.15.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
|
||||||
|
dependencies = [
|
||||||
|
"encode_unicode",
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.45.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "constant_time_eq"
|
name = "constant_time_eq"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
|
@ -424,12 +457,24 @@ dependencies = [
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dyn-clone"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23d2f3407d9a573d666de4b5bdf10569d73ca9478087346697dcbae6244bfbcd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encode_unicode"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.32"
|
version = "0.8.32"
|
||||||
|
|
@ -473,6 +518,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "event-listener"
|
||||||
|
version = "2.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
|
|
@ -811,6 +862,20 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "insta"
|
||||||
|
version = "1.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a3e02c584f4595792d09509a94cdb92a3cef7592b1eb2d9877ee6f527062d0ea"
|
||||||
|
dependencies = [
|
||||||
|
"console",
|
||||||
|
"lazy_static",
|
||||||
|
"linked-hash-map",
|
||||||
|
"serde",
|
||||||
|
"similar",
|
||||||
|
"yaml-rust",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
|
|
@ -918,6 +983,12 @@ dependencies = [
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linked-hash-map"
|
||||||
|
version = "0.5.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
|
|
@ -946,6 +1017,15 @@ version = "0.4.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchers"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||||
|
dependencies = [
|
||||||
|
"regex-automata",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
|
@ -1068,6 +1148,16 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_cpus"
|
||||||
|
version = "1.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.31.1"
|
version = "0.31.1"
|
||||||
|
|
@ -1153,7 +1243,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-targets",
|
"windows-targets 0.48.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1260,9 +1350,24 @@ checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-syntax",
|
"regex-syntax 0.7.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||||
|
dependencies = [
|
||||||
|
"regex-syntax 0.6.29",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.7.2"
|
version = "0.7.2"
|
||||||
|
|
@ -1360,6 +1465,30 @@ dependencies = [
|
||||||
"windows-sys 0.42.0",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schemars"
|
||||||
|
version = "0.8.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f7b0ce13155372a76ee2e1c5ffba1fe61ede73fbea5630d61eee6fac4929c0c"
|
||||||
|
dependencies = [
|
||||||
|
"dyn-clone",
|
||||||
|
"schemars_derive",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schemars_derive"
|
||||||
|
version = "0.8.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e85e2a16b12bdb763244c69ab79363d71db2b4b918a2def53f80b02e0574b13c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"serde_derive_internals",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
@ -1409,6 +1538,17 @@ dependencies = [
|
||||||
"syn 2.0.22",
|
"syn 2.0.22",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive_internals"
|
||||||
|
version = "0.26.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.99"
|
version = "1.0.99"
|
||||||
|
|
@ -1480,6 +1620,12 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "similar"
|
||||||
|
version = "2.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.8"
|
version = "0.4.8"
|
||||||
|
|
@ -1656,6 +1802,7 @@ dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
|
"num_cpus",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
|
|
@ -1779,10 +1926,14 @@ version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77"
|
checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"matchers",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
"sharded-slab",
|
"sharded-slab",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thread_local",
|
"thread_local",
|
||||||
|
"tracing",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
"tracing-log",
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
@ -1808,6 +1959,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"nix",
|
"nix",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"socket2",
|
"socket2",
|
||||||
"ssri",
|
"ssri",
|
||||||
|
|
@ -2041,7 +2193,7 @@ version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets",
|
"windows-targets 0.48.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2059,13 +2211,37 @@ dependencies = [
|
||||||
"windows_x86_64_msvc 0.42.2",
|
"windows_x86_64_msvc 0.42.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.45.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.42.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets",
|
"windows-targets 0.48.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.42.2",
|
||||||
|
"windows_aarch64_msvc 0.42.2",
|
||||||
|
"windows_i686_gnu 0.42.2",
|
||||||
|
"windows_i686_msvc 0.42.2",
|
||||||
|
"windows_x86_64_gnu 0.42.2",
|
||||||
|
"windows_x86_64_gnullvm 0.42.2",
|
||||||
|
"windows_x86_64_msvc 0.42.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2182,6 +2358,15 @@ version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "735a71d46c4d68d71d4b24d03fdc2b98e38cea81730595801db779c04fe80d70"
|
checksum = "735a71d46c4d68d71d4b24d03fdc2b98e38cea81730595801db779c04fe80d70"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yaml-rust"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||||
|
dependencies = [
|
||||||
|
"linked-hash-map",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zip"
|
name = "zip"
|
||||||
version = "0.6.6"
|
version = "0.6.6"
|
||||||
|
|
|
||||||
|
|
@ -10,18 +10,20 @@ crate-type = ["lib", "staticlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
tokio = { version = "1.21", features = ["rt", "macros", "sync", "io-util"] }
|
tokio = { version = "1.21", features = ["rt", "macros", "sync", "io-util", "rt-multi-thread"] }
|
||||||
tun = { version = "0.1", path = "../tun", features = ["serde"] }
|
tun = { version = "0.1", path = "../tun", features = ["serde", "tokio"] }
|
||||||
clap = { version = "4.3.2", features = ["derive"] }
|
clap = { version = "4.3.2", features = ["derive"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-log = "0.1"
|
tracing-log = "0.1"
|
||||||
tracing-journald = "0.3"
|
tracing-journald = "0.3"
|
||||||
tracing-oslog = {git = "https://github.com/Stormshield-robinc/tracing-oslog"}
|
tracing-oslog = {git = "https://github.com/Stormshield-robinc/tracing-oslog"}
|
||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = { version = "0.3" , features = ["std", "env-filter"]}
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
async-channel = "1.9"
|
||||||
|
schemars = "0.8"
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
caps = "0.5.5"
|
caps = "0.5.5"
|
||||||
|
|
@ -30,6 +32,9 @@ libsystemd = "0.6"
|
||||||
[target.'cfg(target_vendor = "apple")'.dependencies]
|
[target.'cfg(target_vendor = "apple")'.dependencies]
|
||||||
nix = { version = "0.26.2" }
|
nix = { version = "0.26.2" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
insta = { version = "1.32.0", features = ["yaml"] }
|
||||||
|
|
||||||
[package.metadata.generate-rpm]
|
[package.metadata.generate-rpm]
|
||||||
assets = [
|
assets = [
|
||||||
{ source = "target/release/burrow", dest = "/usr/bin/burrow", mode = "755" },
|
{ source = "target/release/burrow", dest = "/usr/bin/burrow", mode = "755" },
|
||||||
|
|
|
||||||
15
burrow/src/apple.rs
Normal file
15
burrow/src/apple.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
use tracing::{debug, Subscriber};
|
||||||
|
use tracing::instrument::WithSubscriber;
|
||||||
|
use tracing_oslog::OsLogger;
|
||||||
|
use tracing_subscriber::FmtSubscriber;
|
||||||
|
use tracing_subscriber::layer::SubscriberExt;
|
||||||
|
|
||||||
|
pub use crate::daemon::start_srv;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn initialize_oslog() {
|
||||||
|
let collector = tracing_subscriber::registry()
|
||||||
|
.with(OsLogger::new("com.hackclub.burrow", "backend"));
|
||||||
|
tracing::subscriber::set_global_default(collector).unwrap();
|
||||||
|
debug!("Initialized oslog tracing in libburrow rust FFI");
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,32 @@
|
||||||
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tun::TunOptions;
|
use tun::TunOptions;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
pub enum DaemonCommand {
|
pub enum DaemonCommand {
|
||||||
Start(DaemonStartOptions),
|
Start(DaemonStartOptions),
|
||||||
|
ServerInfo,
|
||||||
|
ServerConfig,
|
||||||
Stop,
|
Stop,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct DaemonStartOptions {
|
pub struct DaemonStartOptions {
|
||||||
pub(super) tun: TunOptions,
|
pub(super) tun: TunOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_daemoncommand_serialization() {
|
||||||
|
insta::assert_snapshot!(
|
||||||
|
serde_json::to_string(&DaemonCommand::Start(DaemonStartOptions::default())).unwrap()
|
||||||
|
);
|
||||||
|
insta::assert_snapshot!(
|
||||||
|
serde_json::to_string(&DaemonCommand::ServerInfo).unwrap()
|
||||||
|
);
|
||||||
|
insta::assert_snapshot!(
|
||||||
|
serde_json::to_string(&DaemonCommand::Stop).unwrap()
|
||||||
|
);
|
||||||
|
insta::assert_snapshot!(
|
||||||
|
serde_json::to_string(&DaemonCommand::ServerConfig).unwrap()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,40 +1,70 @@
|
||||||
|
use tracing::{debug, info, warn};
|
||||||
|
use DaemonResponse;
|
||||||
|
use crate::daemon::response::{DaemonResponseData, ServerConfig, ServerInfo};
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub struct DaemonInstance {
|
pub struct DaemonInstance {
|
||||||
rx: mpsc::Receiver<DaemonCommand>,
|
rx: async_channel::Receiver<DaemonCommand>,
|
||||||
|
sx: async_channel::Sender<DaemonResponse>,
|
||||||
tun_interface: Option<TunInterface>,
|
tun_interface: Option<TunInterface>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DaemonInstance {
|
impl DaemonInstance {
|
||||||
pub fn new(rx: mpsc::Receiver<DaemonCommand>) -> Self {
|
pub fn new(rx: async_channel::Receiver<DaemonCommand>, sx: async_channel::Sender<DaemonResponse>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
rx,
|
rx,
|
||||||
|
sx,
|
||||||
tun_interface: None,
|
tun_interface: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(&mut self) -> Result<()> {
|
async fn proc_command(&mut self, command: DaemonCommand) -> Result<DaemonResponseData> {
|
||||||
while let Some(command) = self.rx.recv().await {
|
info!("Daemon got command: {:?}", command);
|
||||||
match command {
|
match command {
|
||||||
DaemonCommand::Start(options) => {
|
DaemonCommand::Start(st) => {
|
||||||
if self.tun_interface.is_none() {
|
if self.tun_interface.is_none() {
|
||||||
self.tun_interface = Some(options.tun.open()?);
|
debug!("Daemon attempting start tun interface.");
|
||||||
eprintln!("Daemon starting tun interface.");
|
self.tun_interface = Some(st.tun.open()?);
|
||||||
|
info!("Daemon started tun interface");
|
||||||
} else {
|
} else {
|
||||||
eprintln!("Got start, but tun interface already up.");
|
warn!("Got start, but tun interface already up.");
|
||||||
|
}
|
||||||
|
Ok(DaemonResponseData::None)
|
||||||
|
}
|
||||||
|
DaemonCommand::ServerInfo => {
|
||||||
|
match &self.tun_interface {
|
||||||
|
None => {Ok(DaemonResponseData::None)}
|
||||||
|
Some(ti) => {
|
||||||
|
info!("{:?}", ti);
|
||||||
|
Ok(
|
||||||
|
DaemonResponseData::ServerInfo(
|
||||||
|
ServerInfo::try_from(ti)?
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DaemonCommand::Stop => {
|
DaemonCommand::Stop => {
|
||||||
if self.tun_interface.is_some() {
|
if self.tun_interface.is_some() {
|
||||||
self.tun_interface = None;
|
self.tun_interface = None;
|
||||||
eprintln!("Daemon stopping tun interface.");
|
info!("Daemon stopping tun interface.");
|
||||||
} else {
|
} else {
|
||||||
eprintln!("Got stop, but tun interface is not up.")
|
warn!("Got stop, but tun interface is not up.")
|
||||||
}
|
}
|
||||||
|
Ok(DaemonResponseData::None)
|
||||||
|
}
|
||||||
|
DaemonCommand::ServerConfig => {
|
||||||
|
Ok(DaemonResponseData::ServerConfig(ServerConfig::default()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn run(&mut self) -> Result<()> {
|
||||||
|
while let Ok(command) = self.rx.recv().await {
|
||||||
|
let response = self.proc_command(command).await;
|
||||||
|
info!("Daemon response: {:?}", response);
|
||||||
|
self.sx.send(DaemonResponse::new(response)).await?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use tokio::sync::mpsc;
|
||||||
mod command;
|
mod command;
|
||||||
mod instance;
|
mod instance;
|
||||||
mod net;
|
mod net;
|
||||||
|
mod response;
|
||||||
|
|
||||||
use instance::DaemonInstance;
|
use instance::DaemonInstance;
|
||||||
use net::listen;
|
use net::listen;
|
||||||
|
|
@ -11,9 +12,15 @@ use net::listen;
|
||||||
pub use command::{DaemonCommand, DaemonStartOptions};
|
pub use command::{DaemonCommand, DaemonStartOptions};
|
||||||
pub use net::DaemonClient;
|
pub use net::DaemonClient;
|
||||||
|
|
||||||
pub async fn daemon_main() -> Result<()> {
|
#[cfg(target_vendor = "apple")]
|
||||||
let (tx, rx) = mpsc::channel(2);
|
pub use net::start_srv;
|
||||||
let mut inst = DaemonInstance::new(rx);
|
|
||||||
|
|
||||||
tokio::try_join!(inst.run(), listen(tx)).map(|_| ())
|
pub use response::{DaemonResponseData, DaemonResponse, ServerInfo};
|
||||||
|
|
||||||
|
pub async fn daemon_main() -> Result<()> {
|
||||||
|
let (commands_tx, commands_rx) = async_channel::unbounded();
|
||||||
|
let (response_tx, response_rx) = async_channel::unbounded();
|
||||||
|
let mut inst = DaemonInstance::new(commands_rx, response_tx);
|
||||||
|
|
||||||
|
tokio::try_join!(inst.run(), listen(commands_tx, response_rx)).map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
24
burrow/src/daemon/net/apple.rs
Normal file
24
burrow/src/daemon/net/apple.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
use std::thread;
|
||||||
|
use tokio::runtime::Runtime;
|
||||||
|
use tracing::error;
|
||||||
|
use crate::daemon::{daemon_main, DaemonClient};
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn start_srv(){
|
||||||
|
let _handle = thread::spawn(move || {
|
||||||
|
let rt = Runtime::new().unwrap();
|
||||||
|
rt.block_on(async {
|
||||||
|
if let Err(e) = daemon_main().await {
|
||||||
|
error!("Error when starting rpc server: {}", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let rt = Runtime::new().unwrap();
|
||||||
|
rt.block_on(async {
|
||||||
|
loop {
|
||||||
|
if let Ok(_) = DaemonClient::new().await{
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -13,17 +13,19 @@ pub use systemd::{listen, DaemonClient};
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
mod windows;
|
mod windows;
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub use windows::{listen, DaemonClient};
|
pub use windows::{listen, DaemonClient};
|
||||||
|
|
||||||
|
#[cfg(target_vendor = "apple")]
|
||||||
|
mod apple;
|
||||||
|
|
||||||
|
#[cfg(target_vendor = "apple")]
|
||||||
|
pub use apple::start_srv;
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct DaemonRequest {
|
pub struct DaemonRequest {
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
pub command: DaemonCommand,
|
pub command: DaemonCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
|
||||||
pub struct DaemonResponse {
|
|
||||||
// Error types can't be serialized, so this is the second best option.
|
|
||||||
result: std::result::Result<(), String>,
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::os::fd::IntoRawFd;
|
use std::os::fd::IntoRawFd;
|
||||||
|
|
||||||
pub async fn listen(cmd_tx: mpsc::Sender<DaemonCommand>) -> Result<()> {
|
pub async fn listen(cmd_tx: async_channel::Sender<DaemonCommand>, rsp_rx: async_channel::Receiver<DaemonResponse>) -> Result<()> {
|
||||||
if !libsystemd::daemon::booted() || listen_with_systemd(cmd_tx.clone()).await.is_err() {
|
if !libsystemd::daemon::booted() || listen_with_systemd(cmd_tx.clone(), rsp_rx.clone()).await.is_err() {
|
||||||
unix::listen(cmd_tx).await?;
|
unix::listen(cmd_tx, rsp_rx).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn listen_with_systemd(cmd_tx: mpsc::Sender<DaemonCommand>) -> Result<()> {
|
async fn listen_with_systemd(cmd_tx: async_channel::Sender<DaemonCommand>, rsp_rx: async_channel::Receiver<DaemonResponse>) -> Result<()> {
|
||||||
let fds = libsystemd::activation::receive_descriptors(false).unwrap();
|
let fds = libsystemd::activation::receive_descriptors(false)?;
|
||||||
super::unix::listen_with_optional_fd(cmd_tx, Some(fds[0].clone().into_raw_fd())).await
|
super::unix::listen_with_optional_fd(cmd_tx, rsp_rx,Some(fds[0].clone().into_raw_fd())).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type DaemonClient = unix::DaemonClient;
|
pub type DaemonClient = unix::DaemonClient;
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,51 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::{
|
use std::{ascii, io, os::fd::{FromRawFd, RawFd}, os::unix::net::UnixListener as StdUnixListener, path::Path};
|
||||||
os::fd::{FromRawFd, RawFd},
|
use std::hash::Hash;
|
||||||
os::unix::net::UnixListener as StdUnixListener,
|
use std::path::PathBuf;
|
||||||
path::Path,
|
use anyhow::anyhow;
|
||||||
};
|
use log::log;
|
||||||
|
use tracing::info;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
|
io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
|
||||||
net::{UnixListener, UnixStream},
|
net::{UnixListener, UnixStream},
|
||||||
};
|
};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
|
#[cfg(not(target_vendor = "apple"))]
|
||||||
const UNIX_SOCKET_PATH: &str = "/run/burrow.sock";
|
const UNIX_SOCKET_PATH: &str = "/run/burrow.sock";
|
||||||
|
|
||||||
pub async fn listen(cmd_tx: mpsc::Sender<DaemonCommand>) -> Result<()> {
|
#[cfg(target_vendor = "apple")]
|
||||||
listen_with_optional_fd(cmd_tx, None).await
|
const UNIX_SOCKET_PATH: &str = "burrow.sock";
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn fetch_socket_path() -> Option<PathBuf>{
|
||||||
|
let tries = vec![
|
||||||
|
"burrow.sock".to_string(),
|
||||||
|
format!("{}/Library/Containers/com.hackclub.burrow.network/Data/burrow.sock",
|
||||||
|
std::env::var("HOME").unwrap_or_default())
|
||||||
|
.to_string(),
|
||||||
|
];
|
||||||
|
for path in tries{
|
||||||
|
let path = PathBuf::from(path);
|
||||||
|
if path.exists(){
|
||||||
|
return Some(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
fn fetch_socket_path() -> Option<PathBuf>{
|
||||||
|
Some(Path::new(UNIX_SOCKET_PATH).to_path_buf())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn listen(cmd_tx: async_channel::Sender<DaemonCommand>, rsp_rx: async_channel::Receiver<DaemonResponse>) -> Result<()> {
|
||||||
|
listen_with_optional_fd(cmd_tx, rsp_rx, None).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn listen_with_optional_fd(
|
pub(crate) async fn listen_with_optional_fd(
|
||||||
cmd_tx: mpsc::Sender<DaemonCommand>,
|
cmd_tx: async_channel::Sender<DaemonCommand>,
|
||||||
|
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
||||||
raw_fd: Option<RawFd>,
|
raw_fd: Option<RawFd>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let path = Path::new(UNIX_SOCKET_PATH);
|
let path = Path::new(UNIX_SOCKET_PATH);
|
||||||
|
|
@ -32,7 +61,16 @@ pub(crate) async fn listen_with_optional_fd(
|
||||||
listener
|
listener
|
||||||
} else {
|
} else {
|
||||||
// Won't help all that much, if we use the async version of fs.
|
// Won't help all that much, if we use the async version of fs.
|
||||||
std::fs::remove_file(path)?;
|
if let Some(par) = path.parent(){
|
||||||
|
std::fs::create_dir_all(
|
||||||
|
par
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
match std::fs::remove_file(path){
|
||||||
|
Err(e) if e.kind()==io::ErrorKind::NotFound => {Ok(())}
|
||||||
|
stuff => stuff
|
||||||
|
}?;
|
||||||
|
info!("Relative path: {}", path.to_string_lossy());
|
||||||
UnixListener::bind(path)?
|
UnixListener::bind(path)?
|
||||||
};
|
};
|
||||||
loop {
|
loop {
|
||||||
|
|
@ -41,29 +79,35 @@ pub(crate) async fn listen_with_optional_fd(
|
||||||
|
|
||||||
// I'm pretty sure we won't need to manually join / shut this down,
|
// I'm pretty sure we won't need to manually join / shut this down,
|
||||||
// `lines` will return Err during dropping, and this task should exit gracefully.
|
// `lines` will return Err during dropping, and this task should exit gracefully.
|
||||||
tokio::task::spawn(async {
|
let rsp_rxc = rsp_rx.clone();
|
||||||
|
tokio::task::spawn(async move {
|
||||||
let cmd_tx = cmd_tx;
|
let cmd_tx = cmd_tx;
|
||||||
let mut stream = stream;
|
let mut stream = stream;
|
||||||
let (mut read_stream, mut write_stream) = stream.split();
|
let (mut read_stream, mut write_stream) = stream.split();
|
||||||
let buf_reader = BufReader::new(&mut read_stream);
|
let buf_reader = BufReader::new(&mut read_stream);
|
||||||
let mut lines = buf_reader.lines();
|
let mut lines = buf_reader.lines();
|
||||||
while let Ok(Some(line)) = lines.next_line().await {
|
while let Ok(Some(line)) = lines.next_line().await {
|
||||||
let mut res = DaemonResponse { result: Ok(()) };
|
info!("Got line: {}", line);
|
||||||
let command = match serde_json::from_str::<DaemonRequest>(&line) {
|
debug!("Line raw data: {:?}", line.as_bytes());
|
||||||
Ok(req) => Some(req.command),
|
let mut res : DaemonResponse = DaemonResponseData::None.into();
|
||||||
|
let req = match serde_json::from_str::<DaemonRequest>(&line) {
|
||||||
|
Ok(req) => Some(req),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
res.result = Err(format!("{}", e));
|
res.result = Err(e.to_string());
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut res = serde_json::to_string(&res).unwrap();
|
let mut res = serde_json::to_string(&res).unwrap();
|
||||||
res.push('\n');
|
res.push('\n');
|
||||||
|
|
||||||
write_stream.write_all(res.as_bytes()).await.unwrap();
|
|
||||||
|
|
||||||
// I want this to come at the very end so that we always send a reponse back.
|
if let Some(req) = req {
|
||||||
if let Some(command) = command {
|
cmd_tx.send(req.command).await.unwrap();
|
||||||
cmd_tx.send(command).await.unwrap();
|
let res = rsp_rxc.recv().await.unwrap().with_id(req.id);
|
||||||
|
let mut retres = serde_json::to_string(&res).unwrap();
|
||||||
|
retres.push('\n');
|
||||||
|
info!("Sending response: {}", retres);
|
||||||
|
write_stream.write_all(retres.as_bytes()).await.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -76,7 +120,12 @@ pub struct DaemonClient {
|
||||||
|
|
||||||
impl DaemonClient {
|
impl DaemonClient {
|
||||||
pub async fn new() -> Result<Self> {
|
pub async fn new() -> Result<Self> {
|
||||||
Self::new_with_path(UNIX_SOCKET_PATH).await
|
let path = fetch_socket_path()
|
||||||
|
.ok_or(anyhow!("Failed to find socket path"))?;
|
||||||
|
// debug!("found path: {:?}", path);
|
||||||
|
let connection = UnixStream::connect(path).await?;
|
||||||
|
debug!("connected to socket");
|
||||||
|
Ok(Self { connection })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new_with_path(path: &str) -> Result<Self> {
|
pub async fn new_with_path(path: &str) -> Result<Self> {
|
||||||
|
|
@ -86,17 +135,19 @@ impl DaemonClient {
|
||||||
Ok(Self { connection })
|
Ok(Self { connection })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_command(&mut self, command: DaemonCommand) -> Result<()> {
|
pub async fn send_command(&mut self, command: DaemonCommand) -> Result<DaemonResponse> {
|
||||||
let mut command = serde_json::to_string(&DaemonRequest { id: 0, command })?;
|
let mut command = serde_json::to_string(&DaemonRequest { id: 0, command })?;
|
||||||
command.push('\n');
|
command.push('\n');
|
||||||
|
|
||||||
self.connection.write_all(command.as_bytes()).await?;
|
self.connection.write_all(command.as_bytes()).await?;
|
||||||
let buf_reader = BufReader::new(&mut self.connection);
|
let buf_reader = BufReader::new(&mut self.connection);
|
||||||
let mut lines = buf_reader.lines();
|
let mut lines = buf_reader.lines();
|
||||||
// This unwrap *should* never cause issues.
|
let response = lines
|
||||||
let response = lines.next_line().await?.unwrap();
|
.next_line()
|
||||||
|
.await?
|
||||||
|
.ok_or(anyhow!("Failed to read response"))?;
|
||||||
|
debug!("Got raw response: {}", response);
|
||||||
let res: DaemonResponse = serde_json::from_str(&response)?;
|
let res: DaemonResponse = serde_json::from_str(&response)?;
|
||||||
res.result.unwrap();
|
Ok(res)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub async fn listen(_: mpsc::Sender<DaemonCommand>) -> Result<()> {
|
pub async fn listen(_cmd_tx: async_channel::Sender<DaemonCommand>, _rsp_rx: async_channel::Receiver<DaemonResponse>) -> Result<()> {
|
||||||
unimplemented!("This platform does not currently support daemon mode.")
|
unimplemented!("This platform does not currently support daemon mode.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
109
burrow/src/daemon/response.rs
Normal file
109
burrow/src/daemon/response.rs
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tun::TunInterface;
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
|
||||||
|
pub struct DaemonResponse {
|
||||||
|
// Error types can't be serialized, so this is the second best option.
|
||||||
|
pub result: Result<DaemonResponseData, String>,
|
||||||
|
pub id: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DaemonResponse{
|
||||||
|
pub fn new(result: Result<DaemonResponseData, impl ToString>) -> Self{
|
||||||
|
Self{
|
||||||
|
result: result.map_err(|e| e.to_string()),
|
||||||
|
id: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<DaemonResponse> for DaemonResponseData{
|
||||||
|
fn into(self) -> DaemonResponse{
|
||||||
|
DaemonResponse::new(Ok::<DaemonResponseData, String>(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DaemonResponse{
|
||||||
|
pub fn with_id(self, id: u32) -> Self{
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
|
pub struct ServerInfo {
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub ip: Option<String>,
|
||||||
|
pub mtu: Option<i32>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&TunInterface> for ServerInfo{
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
#[cfg(any(target_os="linux",target_vendor="apple"))]
|
||||||
|
fn try_from(server: &TunInterface) -> anyhow::Result<Self> {
|
||||||
|
Ok(
|
||||||
|
ServerInfo{
|
||||||
|
name: server.name().ok(),
|
||||||
|
ip: server.ipv4_addr().ok().map(|ip| ip.to_string()),
|
||||||
|
mtu: server.mtu().ok()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os="linux",target_vendor="apple")))]
|
||||||
|
fn try_from(server: &TunInterface) -> anyhow::Result<Self> {
|
||||||
|
Err(anyhow!("Not implemented in this platform"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
|
pub struct ServerConfig {
|
||||||
|
pub address: Option<String>,
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub mtu: Option<i32>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ServerConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self{
|
||||||
|
address: Some("10.0.0.1".to_string()), // Dummy remote address
|
||||||
|
name: None,
|
||||||
|
mtu: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
|
pub enum DaemonResponseData{
|
||||||
|
ServerInfo(ServerInfo),
|
||||||
|
ServerConfig(ServerConfig),
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_response_serialization() -> anyhow::Result<()>{
|
||||||
|
insta::assert_snapshot!(
|
||||||
|
serde_json::to_string(&DaemonResponse::new(Ok::<DaemonResponseData, String>(DaemonResponseData::None)))?
|
||||||
|
);
|
||||||
|
insta::assert_snapshot!(
|
||||||
|
serde_json::to_string(&DaemonResponse::new(Ok::<DaemonResponseData, String>(DaemonResponseData::ServerInfo(ServerInfo{
|
||||||
|
name: Some("burrow".to_string()),
|
||||||
|
ip: None,
|
||||||
|
mtu: Some(1500)
|
||||||
|
}))))?
|
||||||
|
);
|
||||||
|
insta::assert_snapshot!(
|
||||||
|
serde_json::to_string(&DaemonResponse::new(Err::<DaemonResponseData, String>("error".to_string())))?
|
||||||
|
);
|
||||||
|
insta::assert_snapshot!(
|
||||||
|
serde_json::to_string(&DaemonResponse::new(Ok::<DaemonResponseData, String>(DaemonResponseData::ServerConfig(
|
||||||
|
ServerConfig::default()
|
||||||
|
))))?
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
source: burrow/src/daemon/command.rs
|
||||||
|
expression: "serde_json::to_string(&DaemonCommand::ServerInfo).unwrap()"
|
||||||
|
---
|
||||||
|
"ServerInfo"
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
source: burrow/src/daemon/command.rs
|
||||||
|
expression: "serde_json::to_string(&DaemonCommand::Stop).unwrap()"
|
||||||
|
---
|
||||||
|
"Stop"
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
source: burrow/src/daemon/command.rs
|
||||||
|
expression: "serde_json::to_string(&DaemonCommand::ServerConfig).unwrap()"
|
||||||
|
---
|
||||||
|
"ServerConfig"
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
source: burrow/src/daemon/command.rs
|
||||||
|
expression: "serde_json::to_string(&DaemonCommand::Start(DaemonStartOptions::default())).unwrap()"
|
||||||
|
---
|
||||||
|
{"Start":{"tun":{"name":null,"no_pi":null,"tun_excl":null}}}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
source: burrow/src/daemon/response.rs
|
||||||
|
expression: "serde_json::to_string(&DaemonResponse::new(Ok::<DaemonResponseData,\n String>(DaemonResponseData::ServerInfo(ServerInfo {\n name: Some(\"burrow\".to_string()),\n ip: None,\n mtu: Some(1500),\n }))))?"
|
||||||
|
---
|
||||||
|
{"result":{"Ok":{"ServerInfo":{"name":"burrow","ip":null,"mtu":1500}}},"id":0}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
source: burrow/src/daemon/response.rs
|
||||||
|
expression: "serde_json::to_string(&DaemonResponse::new(Err::<DaemonResponseData,\n String>(\"error\".to_string())))?"
|
||||||
|
---
|
||||||
|
{"result":{"Err":"error"},"id":0}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
source: burrow/src/daemon/response.rs
|
||||||
|
expression: "serde_json::to_string(&DaemonResponse::new(Ok::<DaemonResponseData,\n String>(DaemonResponseData::ServerConfig(ServerConfig::default()))))?"
|
||||||
|
---
|
||||||
|
{"result":{"Ok":{"ServerConfig":{"address":"10.0.0.1","name":null,"mtu":null}}},"id":0}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
source: burrow/src/daemon/response.rs
|
||||||
|
expression: "serde_json::to_string(&DaemonResponse::new(Ok::<DaemonResponseData,\n String>(DaemonResponseData::None)))?"
|
||||||
|
---
|
||||||
|
{"result":{"Ok":"None"},"id":0}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
#![deny(missing_debug_implementations)]
|
#![deny(missing_debug_implementations)]
|
||||||
pub mod ensureroot;
|
pub mod ensureroot;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||||
use std::{
|
use std::{
|
||||||
mem,
|
mem,
|
||||||
|
|
@ -11,6 +13,15 @@ use tun::TunInterface;
|
||||||
|
|
||||||
// TODO Separate start and retrieve functions
|
// TODO Separate start and retrieve functions
|
||||||
|
|
||||||
|
mod daemon;
|
||||||
|
pub use daemon::{DaemonCommand, DaemonResponseData, DaemonStartOptions, DaemonResponse, ServerInfo};
|
||||||
|
|
||||||
|
#[cfg(target_vendor = "apple")]
|
||||||
|
mod apple;
|
||||||
|
|
||||||
|
#[cfg(target_vendor = "apple")]
|
||||||
|
pub use apple::*;
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn retrieve() -> i32 {
|
pub extern "C" fn retrieve() -> i32 {
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,12 @@ use std::mem;
|
||||||
use std::os::fd::FromRawFd;
|
use std::os::fd::FromRawFd;
|
||||||
|
|
||||||
use clap::{Args, Parser, Subcommand};
|
use clap::{Args, Parser, Subcommand};
|
||||||
use tracing::instrument;
|
use tracing::{instrument, Level};
|
||||||
|
|
||||||
use tracing_log::LogTracer;
|
use tracing_log::LogTracer;
|
||||||
use tracing_oslog::OsLogger;
|
use tracing_oslog::OsLogger;
|
||||||
use tracing_subscriber::{prelude::*, FmtSubscriber};
|
use tracing_subscriber::{prelude::*, FmtSubscriber, EnvFilter};
|
||||||
use tokio::io::Result;
|
use anyhow::Result;
|
||||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||||
use burrow::retrieve;
|
use burrow::retrieve;
|
||||||
use tun::TunInterface;
|
use tun::TunInterface;
|
||||||
|
|
@ -17,6 +17,7 @@ use tun::TunInterface;
|
||||||
mod daemon;
|
mod daemon;
|
||||||
|
|
||||||
use daemon::{DaemonClient, DaemonCommand, DaemonStartOptions};
|
use daemon::{DaemonClient, DaemonCommand, DaemonStartOptions};
|
||||||
|
use crate::daemon::DaemonResponseData;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(name = "Burrow")]
|
#[command(name = "Burrow")]
|
||||||
|
|
@ -44,6 +45,10 @@ enum Commands {
|
||||||
Stop,
|
Stop,
|
||||||
/// Start Burrow daemon
|
/// Start Burrow daemon
|
||||||
Daemon(DaemonArgs),
|
Daemon(DaemonArgs),
|
||||||
|
/// Server Info
|
||||||
|
ServerInfo,
|
||||||
|
/// Server config
|
||||||
|
ServerConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
|
|
@ -61,27 +66,38 @@ async fn try_start() -> Result<()> {
|
||||||
client
|
client
|
||||||
.send_command(DaemonCommand::Start(DaemonStartOptions::default()))
|
.send_command(DaemonCommand::Start(DaemonStartOptions::default()))
|
||||||
.await
|
.await
|
||||||
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||||
#[instrument]
|
#[instrument]
|
||||||
async fn try_retrieve() -> Result<()> {
|
async fn try_retrieve() -> Result<()> {
|
||||||
LogTracer::init().context("Failed to initialize LogTracer").unwrap();
|
|
||||||
|
|
||||||
if cfg!(target_os = "linux") || cfg!(target_vendor = "apple") {
|
|
||||||
let maybe_layer = system_log().unwrap();
|
|
||||||
if let Some(layer) = maybe_layer {
|
|
||||||
let logger = layer.with_subscriber(FmtSubscriber::new());
|
|
||||||
tracing::subscriber::set_global_default(logger).context("Failed to set the global tracing subscriber").unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
burrow::ensureroot::ensure_root();
|
burrow::ensureroot::ensure_root();
|
||||||
let iface2 = retrieve();
|
let iface2 = retrieve();
|
||||||
tracing::info!("{}", iface2);
|
tracing::info!("{}", iface2);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn initialize_tracing() -> Result<()> {
|
||||||
|
LogTracer::init().context("Failed to initialize LogTracer")?;
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||||
|
{
|
||||||
|
let maybe_layer = system_log()?;
|
||||||
|
if let Some(layer) = maybe_layer {
|
||||||
|
let logger = layer.with_subscriber(
|
||||||
|
FmtSubscriber::builder()
|
||||||
|
.with_line_number(true)
|
||||||
|
.with_env_filter(EnvFilter::from_default_env())
|
||||||
|
.finish()
|
||||||
|
);
|
||||||
|
tracing::subscriber::set_global_default(logger).context("Failed to set the global tracing subscriber")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||||
async fn try_stop() -> Result<()> {
|
async fn try_stop() -> Result<()> {
|
||||||
let mut client = DaemonClient::new().await?;
|
let mut client = DaemonClient::new().await?;
|
||||||
|
|
@ -89,6 +105,44 @@ async fn try_stop() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||||
|
async fn try_serverinfo() -> Result<()>{
|
||||||
|
let mut client = DaemonClient::new().await?;
|
||||||
|
let res = client.send_command(DaemonCommand::ServerInfo).await?;
|
||||||
|
match res.result {
|
||||||
|
Ok(DaemonResponseData::ServerInfo(si)) => {
|
||||||
|
println!("Got Result! {:?}", si);
|
||||||
|
}
|
||||||
|
Ok(DaemonResponseData::None) => {
|
||||||
|
println!("Server not started.")
|
||||||
|
}
|
||||||
|
Ok(res) => {println!("Unexpected Response: {:?}", res)}
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error when retrieving from server: {}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||||
|
async fn try_serverconfig() -> Result<()>{
|
||||||
|
let mut client = DaemonClient::new().await?;
|
||||||
|
let res = client.send_command(DaemonCommand::ServerConfig).await?;
|
||||||
|
match res.result {
|
||||||
|
Ok(DaemonResponseData::ServerConfig(cfig)) => {
|
||||||
|
println!("Got Result! {:?}", cfig);
|
||||||
|
}
|
||||||
|
Ok(DaemonResponseData::None) => {
|
||||||
|
println!("Server not started.")
|
||||||
|
}
|
||||||
|
Ok(res) => {println!("Unexpected Response: {:?}", res)}
|
||||||
|
Err(e) => {
|
||||||
|
println!("Error when retrieving from server: {}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
|
#[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
|
||||||
async fn try_start() -> Result<()> {
|
async fn try_start() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -104,24 +158,40 @@ async fn try_stop() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
|
||||||
|
async fn try_serverinfo() -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
|
||||||
|
async fn try_serverconfig() -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
#[tokio::main(flavor = "current_thread")]
|
#[tokio::main(flavor = "current_thread")]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
|
initialize_tracing().await?;
|
||||||
tracing::info!("Platform: {}", std::env::consts::OS);
|
tracing::info!("Platform: {}", std::env::consts::OS);
|
||||||
|
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
match &cli.command {
|
match &cli.command {
|
||||||
Commands::Start(..) => {
|
Commands::Start(..) => {
|
||||||
try_start().await.unwrap();
|
try_start().await?;
|
||||||
tracing::info!("FINISHED");
|
tracing::info!("FINISHED");
|
||||||
}
|
}
|
||||||
Commands::Retrieve(..) => {
|
Commands::Retrieve(..) => {
|
||||||
try_retrieve().await.unwrap();
|
try_retrieve().await?;
|
||||||
tracing::info!("FINISHED");
|
tracing::info!("FINISHED");
|
||||||
}
|
}
|
||||||
Commands::Stop => {
|
Commands::Stop => {
|
||||||
try_stop().await.unwrap();
|
try_stop().await?;
|
||||||
}
|
}
|
||||||
Commands::Daemon(_) => daemon::daemon_main().await?,
|
Commands::Daemon(_) => daemon::daemon_main().await?,
|
||||||
|
Commands::ServerInfo => {
|
||||||
|
try_serverinfo().await?
|
||||||
|
}
|
||||||
|
Commands::ServerConfig => {
|
||||||
|
try_serverconfig().await?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -141,5 +211,5 @@ fn system_log() -> anyhow::Result<Option<tracing_journald::Layer>> {
|
||||||
|
|
||||||
#[cfg(target_vendor = "apple")]
|
#[cfg(target_vendor = "apple")]
|
||||||
fn system_log() -> anyhow::Result<Option<OsLogger>> {
|
fn system_log() -> anyhow::Result<Option<OsLogger>> {
|
||||||
Ok(Some(OsLogger::new("com.hackclub.burrow", "default")))
|
Ok(Some(OsLogger::new("com.hackclub.burrow", "burrow-cli")))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,12 @@ byteorder = "1.4"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
serde = { version = "1", features = ["derive"], optional = true }
|
serde = { version = "1", features = ["derive"], optional = true }
|
||||||
|
schemars = { version = "0.8", optional = true }
|
||||||
|
|
||||||
futures = { version = "0.3.28", optional = true }
|
futures = { version = "0.3.28", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
serde = ["dep:serde"]
|
serde = ["dep:serde", "dep:schemars"]
|
||||||
tokio = ["tokio/net", "dep:futures"]
|
tokio = ["tokio/net", "dep:futures"]
|
||||||
|
|
||||||
[target.'cfg(feature = "tokio")'.dev-dependencies]
|
[target.'cfg(feature = "tokio")'.dev-dependencies]
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use std::io::Error;
|
||||||
use super::TunInterface;
|
use super::TunInterface;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize, schemars::JsonSchema))]
|
||||||
pub struct TunOptions {
|
pub struct TunOptions {
|
||||||
/// (Windows + Linux) Name the tun interface.
|
/// (Windows + Linux) Name the tun interface.
|
||||||
pub(crate) name: Option<String>,
|
pub(crate) name: Option<String>,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue