GRPC Server Support
- Deprecates old json-rpc system - Add GRPC daemon over uds
This commit is contained in:
parent
3fbb520a10
commit
e4b0f1660b
28 changed files with 1110 additions and 200 deletions
9
.github/workflows/build-apple.yml
vendored
9
.github/workflows/build-apple.yml
vendored
|
|
@ -1,7 +1,7 @@
|
|||
name: Build Apple Apps
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
|
|
@ -39,6 +39,7 @@ jobs:
|
|||
- aarch64-apple-darwin
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_16.0.app/Contents/Developer
|
||||
PROTOC_VERSION: 3.25.1
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
|
@ -54,6 +55,10 @@ jobs:
|
|||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ join(matrix.rust-targets, ', ') }}
|
||||
- name: Install protoc
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: protoc@${{ env.PROTOC_VERSION }}
|
||||
- name: Build
|
||||
id: build
|
||||
uses: ./.github/actions/build-for-testing
|
||||
|
|
@ -82,4 +87,4 @@ jobs:
|
|||
destination: ${{ matrix.destination }}
|
||||
test-plan: ${{ matrix.xcode-ui-test }}
|
||||
artifact-prefix: ui-tests-${{ matrix.sdk-name }}
|
||||
check-name: Xcode UI Tests (${{ matrix.platform }})
|
||||
check-name: Xcode UI Tests (${{ matrix.platform }})
|
||||
7
.github/workflows/build-rust.yml
vendored
7
.github/workflows/build-rust.yml
vendored
|
|
@ -48,6 +48,7 @@ jobs:
|
|||
CARGO_INCREMENTAL: 0
|
||||
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
|
||||
RUST_BACKTRACE: short
|
||||
PROTOC_VERSION: 3.25.1
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
|
@ -64,6 +65,10 @@ jobs:
|
|||
if: matrix.os == 'windows-2022'
|
||||
shell: bash
|
||||
run: echo "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\Llvm\x64\bin" >> $GITHUB_PATH
|
||||
- name: Install protoc
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: protoc@${{ env.PROTOC_VERSION }}
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
|
|
@ -77,4 +82,4 @@ jobs:
|
|||
run: cargo build --verbose --workspace --all-features --target ${{ join(matrix.targets, ' --target ') }} --target ${{ join(matrix.test-targets, ' --target ') }}
|
||||
- name: Test
|
||||
shell: bash
|
||||
run: cargo test --verbose --workspace --all-features --target ${{ join(matrix.test-targets, ' --target ') }}
|
||||
run: cargo test --verbose --workspace --all-features --target ${{ join(matrix.test-targets, ' --target ') }}
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -7,3 +7,8 @@ target/
|
|||
|
||||
.DS_STORE
|
||||
.idea/
|
||||
|
||||
tmp/
|
||||
|
||||
*.db
|
||||
*.sock
|
||||
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
|
|
@ -15,5 +15,12 @@
|
|||
"rust-analyzer.inlayHints.typeHints.enable": false,
|
||||
"rust-analyzer.linkedProjects": [
|
||||
"./burrow/Cargo.toml"
|
||||
]
|
||||
],
|
||||
"[yaml]": {
|
||||
"editor.insertSpaces": true,
|
||||
"editor.tabSize": 2,
|
||||
"editor.autoIndent": "advanced",
|
||||
"diffEditor.ignoreTrimWhitespace": false,
|
||||
"editor.formatOnSave": false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ else
|
|||
CARGO_PATH="$(dirname $(readlink -f $(which cargo))):/usr/bin"
|
||||
fi
|
||||
|
||||
CARGO_PATH="$(dirname $(readlink -f $(which protoc))):$CARGO_PATH"
|
||||
|
||||
# Run cargo without the various environment variables set by Xcode.
|
||||
# Those variables can confuse cargo and the build scripts it runs.
|
||||
env -i PATH="$CARGO_PATH" CARGO_TARGET_DIR="${CONFIGURATION_TEMP_DIR}/target" IPHONEOS_DEPLOYMENT_TARGET="$IPHONEOS_DEPLOYMENT_TARGET" MACOSX_DEPLOYMENT_TARGET="$MACOSX_DEPLOYMENT_TARGET" cargo build "${CARGO_ARGS[@]}"
|
||||
|
|
|
|||
341
Cargo.lock
generated
341
Cargo.lock
generated
|
|
@ -132,17 +132,38 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22068c0c19514942eefcfd4daf8976ef1aad84e61539f95cd200c35202f80af5"
|
||||
dependencies = [
|
||||
"async-stream-impl 0.2.1",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51"
|
||||
dependencies = [
|
||||
"async-stream-impl",
|
||||
"async-stream-impl 0.3.5",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream-impl"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25f9db3b38af870bf7e5cc649167533b493928e50744e2c30ae350230b414670"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream-impl"
|
||||
version = "0.3.5"
|
||||
|
|
@ -165,6 +186,12 @@ dependencies = [
|
|||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
|
|
@ -392,6 +419,8 @@ dependencies = [
|
|||
"aead",
|
||||
"anyhow",
|
||||
"async-channel",
|
||||
"async-stream 0.2.1",
|
||||
"async-stream 0.2.1",
|
||||
"axum 0.7.5",
|
||||
"base64 0.21.7",
|
||||
"blake2",
|
||||
|
|
@ -404,6 +433,7 @@ dependencies = [
|
|||
"fehler",
|
||||
"futures",
|
||||
"hmac",
|
||||
"hyper-util",
|
||||
"insta",
|
||||
"ip_network",
|
||||
"ip_network_table",
|
||||
|
|
@ -412,15 +442,24 @@ dependencies = [
|
|||
"nix 0.27.1",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"prost 0.13.1",
|
||||
"prost-types 0.13.1",
|
||||
"prost 0.13.2",
|
||||
"prost-types 0.13.2",
|
||||
"rand",
|
||||
"rand_core",
|
||||
"reqwest 0.12.5",
|
||||
"ring",
|
||||
"rusqlite",
|
||||
"rust-ini",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tonic 0.12.2",
|
||||
"tonic-build",
|
||||
"tower",
|
||||
"tracing",
|
||||
"tracing-journald",
|
||||
"tracing-log 0.1.4",
|
||||
|
|
@ -619,9 +658,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "fd326812b3fd01da5bb1af7d340d0d555fd3d4b641e7f1dfcf5962a902952787"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"prost",
|
||||
"prost-types",
|
||||
"tonic",
|
||||
"prost 0.12.3",
|
||||
"prost-types 0.12.3",
|
||||
"tonic 0.10.2",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
|
|
@ -637,18 +676,38 @@ dependencies = [
|
|||
"futures-task",
|
||||
"hdrhistogram",
|
||||
"humantime",
|
||||
"prost-types",
|
||||
"prost-types 0.12.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thread_local",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tonic",
|
||||
"tonic 0.10.2",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"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"
|
||||
|
|
@ -704,6 +763,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"
|
||||
|
|
@ -762,6 +827,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 = "dotenv"
|
||||
version = "0.15.0"
|
||||
|
|
@ -876,6 +950,12 @@ version = "0.2.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7"
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.28"
|
||||
|
|
@ -1057,6 +1137,25 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"http 1.1.0",
|
||||
"indexmap 2.1.0",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
|
|
@ -1215,7 +1314,7 @@ dependencies = [
|
|||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"h2 0.3.24",
|
||||
"http 0.2.11",
|
||||
"http-body 0.4.6",
|
||||
"httparse",
|
||||
|
|
@ -1238,6 +1337,7 @@ dependencies = [
|
|||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"h2 0.4.6",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.0",
|
||||
"httparse",
|
||||
|
|
@ -1279,6 +1379,19 @@ dependencies = [
|
|||
"tokio-io-timeout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-timeout"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793"
|
||||
dependencies = [
|
||||
"hyper 1.4.0",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.5.0"
|
||||
|
|
@ -1615,6 +1728,12 @@ dependencies = [
|
|||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.11"
|
||||
|
|
@ -1762,6 +1881,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"
|
||||
|
|
@ -1832,6 +1961,16 @@ version = "2.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"indexmap 2.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.4"
|
||||
|
|
@ -1925,7 +2064,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive",
|
||||
"prost-derive 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive 0.13.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-build"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"heck",
|
||||
"itertools",
|
||||
"log",
|
||||
"multimap",
|
||||
"once_cell",
|
||||
"petgraph",
|
||||
"prettyplease",
|
||||
"prost 0.13.2",
|
||||
"prost-types 0.13.2",
|
||||
"regex",
|
||||
"syn 2.0.48",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1941,13 +2111,35 @@ dependencies = [
|
|||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-types"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e"
|
||||
dependencies = [
|
||||
"prost",
|
||||
"prost 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-types"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519"
|
||||
dependencies = [
|
||||
"prost 0.13.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2100,7 +2292,7 @@ dependencies = [
|
|||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"h2 0.3.24",
|
||||
"http 0.2.11",
|
||||
"http-body 0.4.6",
|
||||
"hyper 0.14.28",
|
||||
|
|
@ -2197,6 +2389,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"
|
||||
|
|
@ -2404,6 +2607,15 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
|
|
@ -2654,6 +2866,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"
|
||||
|
|
@ -2755,25 +2976,59 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788"
|
||||
dependencies = [
|
||||
"indexmap 2.1.0",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"async-stream 0.3.5",
|
||||
"async-trait",
|
||||
"axum 0.6.20",
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"h2",
|
||||
"h2 0.3.24",
|
||||
"http 0.2.11",
|
||||
"http-body 0.4.6",
|
||||
"hyper 0.14.28",
|
||||
"hyper-timeout",
|
||||
"hyper-timeout 0.4.1",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"prost",
|
||||
"prost 0.12.3",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tower",
|
||||
|
|
@ -2782,6 +3037,49 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad"
|
||||
dependencies = [
|
||||
"async-stream 0.3.5",
|
||||
"async-trait",
|
||||
"axum 0.7.5",
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"h2 0.4.6",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.0",
|
||||
"http-body-util",
|
||||
"hyper 1.4.0",
|
||||
"hyper-timeout 0.5.1",
|
||||
"hyper-util",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"prost 0.13.2",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tonic-build"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe4ee8877250136bd7e3d2331632810a4df4ea5e004656990d8d66d2f5ee8a67"
|
||||
dependencies = [
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"prost-build",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.4.13"
|
||||
|
|
@ -2913,6 +3211,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"
|
||||
|
|
@ -3320,6 +3624,15 @@ version = "0.52.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "557404e450152cd6795bb558bca69e43c585055f4606e3bcae5894fc6dac9ba0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.50.0"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ RUN set -eux && \
|
|||
curl --proto '=https' --tlsv1.2 -sSf https://apt.llvm.org/llvm-snapshot.gpg.key | gpg --dearmor --output $KEYRINGS/llvm.gpg && \
|
||||
echo "deb [signed-by=$KEYRINGS/llvm.gpg] http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm-$LLVM_VERSION main" > /etc/apt/sources.list.d/llvm.list && \
|
||||
apt-get update && \
|
||||
apt-get install --no-install-recommends -y clang-$LLVM_VERSION llvm-$LLVM_VERSION lld-$LLVM_VERSION build-essential sqlite3 libsqlite3-dev musl musl-tools musl-dev && \
|
||||
apt-get install --no-install-recommends -y clang-$LLVM_VERSION llvm-$LLVM_VERSION lld-$LLVM_VERSION build-essential sqlite3 libsqlite3-dev musl musl-tools musl-dev protobuf-compiler libprotobuf-dev && \
|
||||
ln -s clang-$LLVM_VERSION /usr/bin/clang && \
|
||||
ln -s clang /usr/bin/clang++ && \
|
||||
ln -s lld-$LLVM_VERSION /usr/bin/ld.lld && \
|
||||
|
|
|
|||
6
Makefile
6
Makefile
|
|
@ -20,6 +20,12 @@ start:
|
|||
stop:
|
||||
@$(cargo_norm) stop
|
||||
|
||||
status:
|
||||
@$(cargo_norm) server-status
|
||||
|
||||
tunnel-config:
|
||||
@$(cargo_norm) tunnel-config
|
||||
|
||||
test-dns:
|
||||
@sudo route delete 8.8.8.8
|
||||
@sudo route add 8.8.8.8 -interface $(tun)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ tokio = { version = "1.37", features = [
|
|||
"signal",
|
||||
"time",
|
||||
"tracing",
|
||||
"fs",
|
||||
] }
|
||||
tun = { version = "0.1", path = "../tun", features = ["serde", "tokio"] }
|
||||
clap = { version = "4.4", features = ["derive"] }
|
||||
|
|
@ -56,8 +57,17 @@ reqwest = { version = "0.12", default-features = false, features = [
|
|||
"json",
|
||||
"rustls-tls",
|
||||
] }
|
||||
rusqlite = "0.31.0"
|
||||
rusqlite = { version = "0.31.0", features = ["blob"] }
|
||||
dotenv = "0.15.0"
|
||||
tonic = "0.12.0"
|
||||
prost = "0.13.1"
|
||||
prost-types = "0.13.1"
|
||||
tokio-stream = "0.1"
|
||||
async-stream = "0.2"
|
||||
tower = "0.4.13"
|
||||
hyper-util = "0.1.6"
|
||||
toml = "0.8.15"
|
||||
rust-ini = "0.21.0"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
caps = "0.5"
|
||||
|
|
@ -66,7 +76,7 @@ tracing-journald = "0.3"
|
|||
|
||||
[target.'cfg(target_vendor = "apple")'.dependencies]
|
||||
nix = { version = "0.27" }
|
||||
rusqlite = { version = "0.31.0", features = ["bundled"] }
|
||||
rusqlite = { version = "0.31.0", features = ["bundled", "blob"] }
|
||||
|
||||
[dev-dependencies]
|
||||
insta = { version = "1.32", features = ["yaml"] }
|
||||
|
|
@ -83,3 +93,7 @@ pre_uninstall_script = "../package/rpm/pre_uninstall"
|
|||
[features]
|
||||
tokio-console = ["dep:console-subscriber"]
|
||||
bundled = ["rusqlite/bundled"]
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = "0.12.0"
|
||||
|
|
|
|||
4
burrow/build.rs
Normal file
4
burrow/build.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
tonic_build::compile_protos("../proto/burrow.proto")?;
|
||||
Ok(())
|
||||
}
|
||||
BIN
burrow/burrow.db
BIN
burrow/burrow.db
Binary file not shown.
|
|
@ -1,5 +1,7 @@
|
|||
use anyhow::Result;
|
||||
|
||||
use crate::daemon::rpc::grpc_defs::{Network, NetworkType};
|
||||
|
||||
pub static PATH: &str = "./server.sqlite3";
|
||||
|
||||
pub fn init_db() -> Result<()> {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,30 @@
|
|||
use std::{
|
||||
ops::Deref,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use tokio::{sync::RwLock, task::JoinHandle};
|
||||
use rusqlite::Connection;
|
||||
use tokio::sync::{mpsc, watch, Notify, RwLock};
|
||||
use tokio_stream::wrappers::ReceiverStream;
|
||||
use tonic::{Request, Response, Status as RspStatus};
|
||||
use tracing::{debug, info, warn};
|
||||
use tun::tokio::TunInterface;
|
||||
use tun::{tokio::TunInterface, TunOptions};
|
||||
|
||||
use super::rpc::grpc_defs::{
|
||||
networks_server::Networks,
|
||||
tunnel_server::Tunnel,
|
||||
Empty,
|
||||
Network,
|
||||
NetworkDeleteRequest,
|
||||
NetworkListResponse,
|
||||
NetworkReorderRequest,
|
||||
State as RPCTunnelState,
|
||||
TunnelConfigurationResponse,
|
||||
TunnelStatusResponse,
|
||||
};
|
||||
use crate::{
|
||||
daemon::rpc::{
|
||||
DaemonCommand,
|
||||
|
|
@ -17,114 +34,223 @@ use crate::{
|
|||
ServerConfig,
|
||||
ServerInfo,
|
||||
},
|
||||
database::{get_connection, load_interface},
|
||||
database::{
|
||||
add_network,
|
||||
delete_network,
|
||||
get_connection,
|
||||
list_networks,
|
||||
load_interface,
|
||||
reorder_network,
|
||||
},
|
||||
wireguard::{Config, Interface},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum RunState {
|
||||
Running(JoinHandle<Result<()>>),
|
||||
Running,
|
||||
Idle,
|
||||
}
|
||||
|
||||
pub struct DaemonInstance {
|
||||
rx: async_channel::Receiver<DaemonCommand>,
|
||||
sx: async_channel::Sender<DaemonResponse>,
|
||||
subx: async_channel::Sender<DaemonNotification>,
|
||||
impl RunState {
|
||||
pub fn to_rpc(&self) -> RPCTunnelState {
|
||||
match self {
|
||||
RunState::Running => RPCTunnelState::Running,
|
||||
RunState::Idle => RPCTunnelState::Stopped,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DaemonRPCServer {
|
||||
tun_interface: Arc<RwLock<Option<TunInterface>>>,
|
||||
wg_interface: Arc<RwLock<Interface>>,
|
||||
config: Arc<RwLock<Config>>,
|
||||
db_path: Option<PathBuf>,
|
||||
wg_state: RunState,
|
||||
wg_state_chan: (watch::Sender<RunState>, watch::Receiver<RunState>),
|
||||
network_update_chan: (watch::Sender<()>, watch::Receiver<()>),
|
||||
}
|
||||
|
||||
impl DaemonInstance {
|
||||
impl DaemonRPCServer {
|
||||
pub fn new(
|
||||
rx: async_channel::Receiver<DaemonCommand>,
|
||||
sx: async_channel::Sender<DaemonResponse>,
|
||||
subx: async_channel::Sender<DaemonNotification>,
|
||||
wg_interface: Arc<RwLock<Interface>>,
|
||||
config: Arc<RwLock<Config>>,
|
||||
db_path: Option<&Path>,
|
||||
) -> Self {
|
||||
Self {
|
||||
rx,
|
||||
sx,
|
||||
subx,
|
||||
wg_interface,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
tun_interface: Arc::new(RwLock::new(None)),
|
||||
wg_interface,
|
||||
config,
|
||||
db_path: db_path.map(|p| p.to_owned()),
|
||||
wg_state: RunState::Idle,
|
||||
}
|
||||
wg_state_chan: watch::channel(RunState::Idle),
|
||||
network_update_chan: watch::channel(()),
|
||||
})
|
||||
}
|
||||
|
||||
async fn proc_command(&mut self, command: DaemonCommand) -> Result<DaemonResponseData> {
|
||||
info!("Daemon got command: {:?}", command);
|
||||
match command {
|
||||
DaemonCommand::Start(st) => {
|
||||
match self.wg_state {
|
||||
RunState::Running(_) => {
|
||||
warn!("Got start, but tun interface already up.");
|
||||
}
|
||||
RunState::Idle => {
|
||||
let tun_if = st.tun.open()?;
|
||||
debug!("Setting tun on wg_interface");
|
||||
self.wg_interface.read().await.set_tun(tun_if).await;
|
||||
debug!("tun set on wg_interface");
|
||||
|
||||
debug!("Setting tun_interface");
|
||||
self.tun_interface = self.wg_interface.read().await.get_tun();
|
||||
debug!("tun_interface set: {:?}", self.tun_interface);
|
||||
|
||||
debug!("Cloning wg_interface");
|
||||
let tmp_wg = self.wg_interface.clone();
|
||||
let run_task = tokio::spawn(async move {
|
||||
let twlock = tmp_wg.read().await;
|
||||
twlock.run().await
|
||||
});
|
||||
self.wg_state = RunState::Running(run_task);
|
||||
info!("Daemon started tun interface");
|
||||
}
|
||||
}
|
||||
Ok(DaemonResponseData::None)
|
||||
}
|
||||
DaemonCommand::ServerInfo => match &self.tun_interface.read().await.as_ref() {
|
||||
None => Ok(DaemonResponseData::None),
|
||||
Some(ti) => {
|
||||
info!("{:?}", ti);
|
||||
Ok(DaemonResponseData::ServerInfo(ServerInfo::try_from(
|
||||
ti.inner.get_ref(),
|
||||
)?))
|
||||
}
|
||||
},
|
||||
DaemonCommand::Stop => {
|
||||
self.wg_interface.read().await.remove_tun().await;
|
||||
self.wg_state = RunState::Idle;
|
||||
Ok(DaemonResponseData::None)
|
||||
}
|
||||
DaemonCommand::ServerConfig => {
|
||||
Ok(DaemonResponseData::ServerConfig(ServerConfig::default()))
|
||||
}
|
||||
DaemonCommand::ReloadConfig(interface_id) => {
|
||||
let conn = get_connection(self.db_path.as_deref())?;
|
||||
let cfig = load_interface(&conn, &interface_id)?;
|
||||
*self.config.write().await = cfig;
|
||||
self.subx
|
||||
.send(DaemonNotification::ConfigChange(ServerConfig::try_from(
|
||||
&self.config.read().await.to_owned(),
|
||||
)?))
|
||||
.await?;
|
||||
Ok(DaemonResponseData::None)
|
||||
}
|
||||
}
|
||||
pub fn get_connection(&self) -> Result<Connection, RspStatus> {
|
||||
get_connection(self.db_path.as_deref()).map_err(proc_err)
|
||||
}
|
||||
|
||||
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(())
|
||||
async fn set_wg_state(&self, state: RunState) -> Result<(), RspStatus> {
|
||||
self.wg_state_chan.0.send(state).map_err(proc_err)
|
||||
}
|
||||
|
||||
async fn get_wg_state(&self) -> RunState {
|
||||
self.wg_state_chan.1.borrow().to_owned()
|
||||
}
|
||||
|
||||
async fn notify_network_update(&self) -> Result<(), RspStatus> {
|
||||
self.network_update_chan.0.send(()).map_err(proc_err)
|
||||
}
|
||||
}
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl Tunnel for DaemonRPCServer {
|
||||
type TunnelConfigurationStream = ReceiverStream<Result<TunnelConfigurationResponse, RspStatus>>;
|
||||
type TunnelStatusStream = ReceiverStream<Result<TunnelStatusResponse, RspStatus>>;
|
||||
|
||||
async fn tunnel_configuration(
|
||||
&self,
|
||||
_request: Request<Empty>,
|
||||
) -> Result<Response<Self::TunnelConfigurationStream>, RspStatus> {
|
||||
let (tx, rx) = mpsc::channel(10);
|
||||
tokio::spawn(async move {
|
||||
let serv_config = ServerConfig::default();
|
||||
tx.send(Ok(TunnelConfigurationResponse {
|
||||
mtu: serv_config.mtu.unwrap_or(1000),
|
||||
addresses: serv_config.address,
|
||||
}))
|
||||
.await
|
||||
});
|
||||
Ok(Response::new(ReceiverStream::new(rx)))
|
||||
}
|
||||
|
||||
async fn tunnel_start(&self, _request: Request<Empty>) -> Result<Response<Empty>, RspStatus> {
|
||||
let wg_state = self.get_wg_state().await;
|
||||
match wg_state {
|
||||
RunState::Idle => {
|
||||
let tun_if = TunOptions::new().open()?;
|
||||
debug!("Setting tun on wg_interface");
|
||||
self.tun_interface.write().await.replace(tun_if);
|
||||
self.wg_interface
|
||||
.write()
|
||||
.await
|
||||
.set_tun_ref(self.tun_interface.clone())
|
||||
.await;
|
||||
debug!("tun set on wg_interface");
|
||||
|
||||
debug!("Setting tun_interface");
|
||||
debug!("tun_interface set: {:?}", self.tun_interface);
|
||||
|
||||
debug!("Cloning wg_interface");
|
||||
let tmp_wg = self.wg_interface.clone();
|
||||
let run_task = tokio::spawn(async move {
|
||||
let twlock = tmp_wg.read().await;
|
||||
twlock.run().await
|
||||
});
|
||||
self.set_wg_state(RunState::Running).await?;
|
||||
}
|
||||
|
||||
RunState::Running => {
|
||||
warn!("Got start, but tun interface already up.");
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(Response::new(Empty {}));
|
||||
}
|
||||
|
||||
async fn tunnel_stop(&self, _request: Request<Empty>) -> Result<Response<Empty>, RspStatus> {
|
||||
self.wg_interface.write().await.remove_tun().await;
|
||||
self.set_wg_state(RunState::Idle).await?;
|
||||
return Ok(Response::new(Empty {}));
|
||||
}
|
||||
|
||||
async fn tunnel_status(
|
||||
&self,
|
||||
_request: Request<Empty>,
|
||||
) -> Result<Response<Self::TunnelStatusStream>, RspStatus> {
|
||||
let (tx, rx) = mpsc::channel(10);
|
||||
let mut state_rx = self.wg_state_chan.1.clone();
|
||||
tokio::spawn(async move {
|
||||
let cur = state_rx.borrow_and_update().to_owned();
|
||||
tx.send(Ok(status_rsp(cur))).await;
|
||||
loop {
|
||||
state_rx.changed().await.unwrap();
|
||||
let cur = state_rx.borrow().to_owned();
|
||||
let res = tx.send(Ok(status_rsp(cur))).await;
|
||||
if res.is_err() {
|
||||
eprintln!("Tunnel status channel closed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
Ok(Response::new(ReceiverStream::new(rx)))
|
||||
}
|
||||
}
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl Networks for DaemonRPCServer {
|
||||
type NetworkListStream = ReceiverStream<Result<NetworkListResponse, RspStatus>>;
|
||||
|
||||
async fn network_add(&self, request: Request<Network>) -> Result<Response<Empty>, RspStatus> {
|
||||
let conn = self.get_connection()?;
|
||||
let network = request.into_inner();
|
||||
add_network(&conn, &network).map_err(proc_err)?;
|
||||
self.notify_network_update().await?;
|
||||
Ok(Response::new(Empty {}))
|
||||
}
|
||||
|
||||
async fn network_list(
|
||||
&self,
|
||||
_request: Request<Empty>,
|
||||
) -> Result<Response<Self::NetworkListStream>, RspStatus> {
|
||||
debug!("Mock network_list called");
|
||||
let (tx, rx) = mpsc::channel(10);
|
||||
let conn = self.get_connection()?;
|
||||
let mut sub = self.network_update_chan.1.clone();
|
||||
tokio::spawn(async move {
|
||||
loop {
|
||||
let networks = list_networks(&conn)
|
||||
.map(|res| NetworkListResponse { network: res })
|
||||
.map_err(proc_err);
|
||||
let res = tx.send(networks).await;
|
||||
if res.is_err() {
|
||||
eprintln!("Network list channel closed");
|
||||
break;
|
||||
}
|
||||
sub.changed().await.unwrap();
|
||||
}
|
||||
});
|
||||
Ok(Response::new(ReceiverStream::new(rx)))
|
||||
}
|
||||
|
||||
async fn network_reorder(
|
||||
&self,
|
||||
request: Request<NetworkReorderRequest>,
|
||||
) -> Result<Response<Empty>, RspStatus> {
|
||||
let conn = self.get_connection()?;
|
||||
reorder_network(&conn, request.into_inner()).map_err(proc_err)?;
|
||||
self.notify_network_update().await?;
|
||||
Ok(Response::new(Empty {}))
|
||||
}
|
||||
|
||||
async fn network_delete(
|
||||
&self,
|
||||
request: Request<NetworkDeleteRequest>,
|
||||
) -> Result<Response<Empty>, RspStatus> {
|
||||
let conn = self.get_connection()?;
|
||||
delete_network(&conn, request.into_inner()).map_err(proc_err)?;
|
||||
self.notify_network_update().await?;
|
||||
Ok(Response::new(Empty {}))
|
||||
}
|
||||
}
|
||||
|
||||
fn proc_err(err: impl ToString) -> RspStatus {
|
||||
RspStatus::internal(err.to_string())
|
||||
}
|
||||
|
||||
fn status_rsp(state: RunState) -> TunnelStatusResponse {
|
||||
TunnelStatusResponse {
|
||||
state: state.to_rpc().into(),
|
||||
start: None, // TODO: Add timestamp
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,20 @@ mod instance;
|
|||
mod net;
|
||||
pub mod rpc;
|
||||
|
||||
use anyhow::Result;
|
||||
use instance::DaemonInstance;
|
||||
pub use net::{DaemonClient, Listener};
|
||||
use anyhow::{Error as AhError, Result};
|
||||
use instance::DaemonRPCServer;
|
||||
pub use net::{get_socket_path, DaemonClient};
|
||||
pub use rpc::{DaemonCommand, DaemonResponseData, DaemonStartOptions};
|
||||
use tokio::sync::{Notify, RwLock};
|
||||
use tokio::{
|
||||
net::UnixListener,
|
||||
sync::{Notify, RwLock},
|
||||
};
|
||||
use tokio_stream::wrappers::UnixListenerStream;
|
||||
use tonic::transport::Server;
|
||||
use tracing::{error, info};
|
||||
|
||||
use crate::{
|
||||
daemon::rpc::grpc_defs::{networks_server::NetworksServer, tunnel_server::TunnelServer},
|
||||
database::{get_connection, load_interface},
|
||||
wireguard::Interface,
|
||||
};
|
||||
|
|
@ -22,52 +28,36 @@ pub async fn daemon_main(
|
|||
db_path: Option<&Path>,
|
||||
notify_ready: Option<Arc<Notify>>,
|
||||
) -> Result<()> {
|
||||
let (commands_tx, commands_rx) = async_channel::unbounded();
|
||||
let (response_tx, response_rx) = async_channel::unbounded();
|
||||
let (subscribe_tx, subscribe_rx) = async_channel::unbounded();
|
||||
|
||||
let listener = if let Some(path) = socket_path {
|
||||
info!("Creating listener... {:?}", path);
|
||||
Listener::new_with_path(commands_tx, response_rx, subscribe_rx, path)
|
||||
} else {
|
||||
info!("Creating listener...");
|
||||
Listener::new(commands_tx, response_rx, subscribe_rx)
|
||||
};
|
||||
if let Some(n) = notify_ready {
|
||||
n.notify_one()
|
||||
}
|
||||
let listener = listener?;
|
||||
let conn = get_connection(db_path)?;
|
||||
let config = load_interface(&conn, "1")?;
|
||||
let iface: Interface = config.clone().try_into()?;
|
||||
let mut instance = DaemonInstance::new(
|
||||
commands_rx,
|
||||
response_tx,
|
||||
subscribe_tx,
|
||||
Arc::new(RwLock::new(iface)),
|
||||
let burrow_server = DaemonRPCServer::new(
|
||||
Arc::new(RwLock::new(config.clone().try_into()?)),
|
||||
Arc::new(RwLock::new(config)),
|
||||
db_path,
|
||||
);
|
||||
db_path.clone(),
|
||||
)?;
|
||||
let spp = socket_path.clone();
|
||||
let tmp = get_socket_path();
|
||||
let sock_path = spp.unwrap_or(Path::new(tmp.as_str()));
|
||||
if sock_path.exists() {
|
||||
std::fs::remove_file(sock_path)?;
|
||||
}
|
||||
let uds = UnixListener::bind(sock_path)?;
|
||||
let serve_job = tokio::spawn(async move {
|
||||
let uds_stream = UnixListenerStream::new(uds);
|
||||
let _srv = Server::builder()
|
||||
.add_service(TunnelServer::new(burrow_server.clone()))
|
||||
.add_service(NetworksServer::new(burrow_server))
|
||||
.serve_with_incoming(uds_stream)
|
||||
.await?;
|
||||
Ok::<(), AhError>(())
|
||||
});
|
||||
|
||||
info!("Starting daemon...");
|
||||
|
||||
let main_job = tokio::spawn(async move {
|
||||
let result = instance.run().await;
|
||||
if let Err(e) = result.as_ref() {
|
||||
error!("Instance exited: {}", e);
|
||||
}
|
||||
result
|
||||
});
|
||||
|
||||
let listener_job = tokio::spawn(async move {
|
||||
let result = listener.run().await;
|
||||
if let Err(e) = result.as_ref() {
|
||||
error!("Listener exited: {}", e);
|
||||
}
|
||||
result
|
||||
});
|
||||
|
||||
tokio::try_join!(main_job, listener_job)
|
||||
tokio::try_join!(serve_job)
|
||||
.map(|_| ())
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,11 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
mod unix;
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
pub use unix::{DaemonClient, Listener};
|
||||
pub use unix::{get_socket_path, DaemonClient, Listener};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
mod windows;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::{DaemonClient, Listener};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ const UNIX_SOCKET_PATH: &str = "/run/burrow.sock";
|
|||
#[cfg(target_vendor = "apple")]
|
||||
const UNIX_SOCKET_PATH: &str = "burrow.sock";
|
||||
|
||||
fn get_socket_path() -> String {
|
||||
pub fn get_socket_path() -> String {
|
||||
if std::env::var("BURROW_SOCKET_PATH").is_ok() {
|
||||
return std::env::var("BURROW_SOCKET_PATH").unwrap();
|
||||
}
|
||||
|
|
@ -36,7 +36,7 @@ pub struct Listener {
|
|||
cmd_tx: async_channel::Sender<DaemonCommand>,
|
||||
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
||||
sub_chan: async_channel::Receiver<DaemonNotification>,
|
||||
inner: UnixListener,
|
||||
pub inner: UnixListener,
|
||||
}
|
||||
|
||||
impl Listener {
|
||||
|
|
|
|||
31
burrow/src/daemon/rpc/client.rs
Normal file
31
burrow/src/daemon/rpc/client.rs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
use anyhow::Result;
|
||||
use hyper_util::rt::TokioIo;
|
||||
use tokio::net::UnixStream;
|
||||
use tonic::transport::{Endpoint, Uri};
|
||||
use tower::service_fn;
|
||||
|
||||
use super::grpc_defs::{networks_client::NetworksClient, tunnel_client::TunnelClient};
|
||||
use crate::daemon::get_socket_path;
|
||||
|
||||
pub struct BurrowClient<T> {
|
||||
pub networks_client: NetworksClient<T>,
|
||||
pub tunnel_client: TunnelClient<T>,
|
||||
}
|
||||
|
||||
impl BurrowClient<tonic::transport::Channel> {
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
pub async fn from_uds() -> Result<Self> {
|
||||
let channel = Endpoint::try_from("http://[::]:50051")? // NOTE: this is a hack(?)
|
||||
.connect_with_connector(service_fn(|_: Uri| async {
|
||||
let sock_path = get_socket_path();
|
||||
Ok::<_, std::io::Error>(TokioIo::new(UnixStream::connect(sock_path).await?))
|
||||
}))
|
||||
.await?;
|
||||
let nw_client = NetworksClient::new(channel.clone());
|
||||
let tun_client = TunnelClient::new(channel.clone());
|
||||
Ok(BurrowClient {
|
||||
networks_client: nw_client,
|
||||
tunnel_client: tun_client,
|
||||
})
|
||||
}
|
||||
}
|
||||
5
burrow/src/daemon/rpc/grpc_defs.rs
Normal file
5
burrow/src/daemon/rpc/grpc_defs.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
pub use burrowgrpc::*;
|
||||
|
||||
mod burrowgrpc {
|
||||
tonic::include_proto!("burrow");
|
||||
}
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
pub mod client;
|
||||
pub mod grpc_defs;
|
||||
pub mod notification;
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
|
||||
pub use client::BurrowClient;
|
||||
pub use notification::DaemonNotification;
|
||||
pub use request::{DaemonCommand, DaemonRequest, DaemonStartOptions};
|
||||
pub use response::{DaemonResponse, DaemonResponseData, ServerConfig, ServerInfo};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,15 @@ use std::path::Path;
|
|||
use anyhow::Result;
|
||||
use rusqlite::{params, Connection};
|
||||
|
||||
use crate::wireguard::config::{Config, Interface, Peer};
|
||||
use crate::{
|
||||
daemon::rpc::grpc_defs::{
|
||||
Network as RPCNetwork,
|
||||
NetworkDeleteRequest,
|
||||
NetworkReorderRequest,
|
||||
NetworkType,
|
||||
},
|
||||
wireguard::config::{Config, Interface, Peer},
|
||||
};
|
||||
|
||||
#[cfg(target_vendor = "apple")]
|
||||
const DB_PATH: &str = "burrow.db";
|
||||
|
|
@ -30,8 +38,20 @@ const CREATE_WG_PEER_TABLE: &str = "CREATE TABLE IF NOT EXISTS wg_peer (
|
|||
)";
|
||||
|
||||
const CREATE_NETWORK_TABLE: &str = "CREATE TABLE IF NOT EXISTS network (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
type TEXT NOT NULL,
|
||||
payload BLOB,
|
||||
idx INTEGER,
|
||||
interface_id INT REFERENCES wg_interface(id) ON UPDATE CASCADE
|
||||
)";
|
||||
);
|
||||
CREATE TRIGGER IF NOT EXISTS increment_network_idx
|
||||
AFTER INSERT ON network
|
||||
BEGIN
|
||||
UPDATE network
|
||||
SET idx = (SELECT COALESCE(MAX(idx), 0) + 1 FROM network)
|
||||
WHERE id = NEW.id;
|
||||
END;
|
||||
";
|
||||
|
||||
pub fn initialize_tables(conn: &Connection) -> Result<()> {
|
||||
conn.execute(CREATE_WG_INTERFACE_TABLE, [])?;
|
||||
|
|
@ -40,20 +60,6 @@ pub fn initialize_tables(conn: &Connection) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_lst(s: &str) -> Vec<String> {
|
||||
if s.is_empty() {
|
||||
return vec![];
|
||||
}
|
||||
s.split(',').map(|s| s.to_string()).collect()
|
||||
}
|
||||
|
||||
fn to_lst<T: ToString>(v: &Vec<T>) -> String {
|
||||
v.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(",")
|
||||
}
|
||||
|
||||
pub fn load_interface(conn: &Connection, interface_id: &str) -> Result<Config> {
|
||||
let iface = conn.query_row(
|
||||
"SELECT private_key, dns, address, listen_port, mtu FROM wg_interface WHERE id = ?",
|
||||
|
|
@ -99,7 +105,7 @@ pub fn dump_interface(conn: &Connection, config: &Config) -> Result<()> {
|
|||
cif.private_key,
|
||||
to_lst(&cif.dns),
|
||||
to_lst(&cif.address),
|
||||
cif.listen_port,
|
||||
cif.listen_port.unwrap_or(51820),
|
||||
cif.mtu
|
||||
])?;
|
||||
let interface_id = conn.last_insert_rowid();
|
||||
|
|
@ -127,10 +133,75 @@ pub fn get_connection(path: Option<&Path>) -> Result<Connection> {
|
|||
Ok(Connection::open(p)?)
|
||||
}
|
||||
|
||||
pub fn add_network(conn: &Connection, network: &RPCNetwork) -> Result<()> {
|
||||
let mut stmt = conn.prepare("INSERT INTO network (id, type, payload) VALUES (?, ?, ?)")?;
|
||||
stmt.execute(params![
|
||||
network.id,
|
||||
network.r#type().as_str_name(),
|
||||
&network.payload
|
||||
])?;
|
||||
if network.r#type() == NetworkType::WireGuard {
|
||||
let payload_str = String::from_utf8(network.payload.clone())?;
|
||||
let wg_config = Config::from_content_fmt(&payload_str, "ini")?;
|
||||
dump_interface(conn, &wg_config)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn list_networks(conn: &Connection) -> Result<Vec<RPCNetwork>> {
|
||||
let mut stmt = conn.prepare("SELECT id, type, payload FROM network ORDER BY idx")?;
|
||||
let networks: Vec<RPCNetwork> = stmt
|
||||
.query_map([], |row| {
|
||||
println!("row: {:?}", row);
|
||||
let network_id: i32 = row.get(0)?;
|
||||
let network_type: String = row.get(1)?;
|
||||
let network_type = NetworkType::from_str_name(network_type.as_str())
|
||||
.ok_or(rusqlite::Error::InvalidQuery)?;
|
||||
let payload: Vec<u8> = row.get(2)?;
|
||||
Ok(RPCNetwork {
|
||||
id: network_id,
|
||||
r#type: network_type.into(),
|
||||
payload: payload.into(),
|
||||
})
|
||||
})?
|
||||
.collect::<Result<Vec<RPCNetwork>, rusqlite::Error>>()?;
|
||||
Ok(networks)
|
||||
}
|
||||
|
||||
pub fn reorder_network(conn: &Connection, req: NetworkReorderRequest) -> Result<()> {
|
||||
let mut stmt = conn.prepare("UPDATE network SET idx = ? WHERE id = ?")?;
|
||||
let res = stmt.execute(params![req.index, req.id])?;
|
||||
if res == 0 {
|
||||
return Err(anyhow::anyhow!("No such network exists"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete_network(conn: &Connection, req: NetworkDeleteRequest) -> Result<()> {
|
||||
let mut stmt = conn.prepare("DELETE FROM network WHERE id = ?")?;
|
||||
let res = stmt.execute(params![req.id])?;
|
||||
if res == 0 {
|
||||
return Err(anyhow::anyhow!("No such network exists"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_lst(s: &str) -> Vec<String> {
|
||||
if s.is_empty() {
|
||||
return vec![];
|
||||
}
|
||||
s.split(',').map(|s| s.to_string()).collect()
|
||||
}
|
||||
|
||||
fn to_lst<T: ToString>(v: &Vec<T>) -> String {
|
||||
v.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(",")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::Path;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -11,8 +11,7 @@ mod wireguard;
|
|||
mod auth;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
use daemon::{DaemonClient, DaemonCommand, DaemonStartOptions};
|
||||
use tun::TunOptions;
|
||||
use daemon::{DaemonClient, DaemonCommand};
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
use crate::daemon::DaemonResponseData;
|
||||
|
|
@ -20,6 +19,9 @@ use crate::daemon::DaemonResponseData;
|
|||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
pub mod database;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
use crate::daemon::rpc::{grpc_defs::Empty, BurrowClient};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "Burrow")]
|
||||
#[command(author = "Hack Club <team@hackclub.com>")]
|
||||
|
|
@ -52,13 +54,24 @@ enum Commands {
|
|||
ReloadConfig(ReloadConfigArgs),
|
||||
/// Authentication server
|
||||
AuthServer,
|
||||
/// Server Status
|
||||
ServerStatus,
|
||||
/// Tunnel Config
|
||||
TunnelConfig,
|
||||
/// Add Network
|
||||
NetworkAdd(NetworkAddArgs),
|
||||
/// List Networks
|
||||
NetworkList,
|
||||
/// Reorder Network
|
||||
NetworkReorder(NetworkReorderArgs),
|
||||
/// Delete Network
|
||||
NetworkDelete(NetworkDeleteArgs),
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct ReloadConfigArgs {
|
||||
#[clap(long, short)]
|
||||
interface_id: String,
|
||||
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
|
|
@ -67,21 +80,132 @@ struct StartArgs {}
|
|||
#[derive(Args)]
|
||||
struct DaemonArgs {}
|
||||
|
||||
#[derive(Args)]
|
||||
struct NetworkAddArgs {
|
||||
id: i32,
|
||||
network_type: i32,
|
||||
payload_path: String,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct NetworkReorderArgs {
|
||||
id: i32,
|
||||
index: i32,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct NetworkDeleteArgs {
|
||||
id: i32,
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
async fn try_start() -> Result<()> {
|
||||
let mut client = DaemonClient::new().await?;
|
||||
client
|
||||
.send_command(DaemonCommand::Start(DaemonStartOptions {
|
||||
tun: TunOptions::new().address(vec!["10.13.13.2", "::2"]),
|
||||
}))
|
||||
.await
|
||||
.map(|_| ())
|
||||
let mut client = BurrowClient::from_uds().await?;
|
||||
let res = client.tunnel_client.tunnel_start(Empty {}).await?;
|
||||
println!("Got results! {:?}", res);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
async fn try_stop() -> Result<()> {
|
||||
let mut client = DaemonClient::new().await?;
|
||||
client.send_command(DaemonCommand::Stop).await?;
|
||||
let mut client = BurrowClient::from_uds().await?;
|
||||
let res = client.tunnel_client.tunnel_stop(Empty {}).await?;
|
||||
println!("Got results! {:?}", res);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
async fn try_serverstatus() -> Result<()> {
|
||||
let mut client = BurrowClient::from_uds().await?;
|
||||
let mut res = client
|
||||
.tunnel_client
|
||||
.tunnel_status(Empty {})
|
||||
.await?
|
||||
.into_inner();
|
||||
if let Some(st) = res.message().await? {
|
||||
println!("Server Status: {:?}", st);
|
||||
} else {
|
||||
println!("Server Status is None");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
async fn try_tun_config() -> Result<()> {
|
||||
let mut client = BurrowClient::from_uds().await?;
|
||||
let mut res = client
|
||||
.tunnel_client
|
||||
.tunnel_configuration(Empty {})
|
||||
.await?
|
||||
.into_inner();
|
||||
if let Some(config) = res.message().await? {
|
||||
println!("Tunnel Config: {:?}", config);
|
||||
} else {
|
||||
println!("Tunnel Config is None");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
async fn try_network_add(id: i32, network_type: i32, payload_path: &str) -> Result<()> {
|
||||
use tokio::{fs::File, io::AsyncReadExt};
|
||||
|
||||
use crate::daemon::rpc::grpc_defs::Network;
|
||||
|
||||
let mut file = File::open(payload_path).await?;
|
||||
let mut payload = Vec::new();
|
||||
file.read_to_end(&mut payload).await?;
|
||||
|
||||
let mut client = BurrowClient::from_uds().await?;
|
||||
let network = Network {
|
||||
id,
|
||||
r#type: network_type,
|
||||
payload,
|
||||
};
|
||||
let res = client.networks_client.network_add(network).await?;
|
||||
println!("Network Add Response: {:?}", res);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
async fn try_network_list() -> Result<()> {
|
||||
let mut client = BurrowClient::from_uds().await?;
|
||||
let mut res = client
|
||||
.networks_client
|
||||
.network_list(Empty {})
|
||||
.await?
|
||||
.into_inner();
|
||||
while let Some(network_list) = res.message().await? {
|
||||
println!("Network List: {:?}", network_list);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
async fn try_network_reorder(id: i32, index: i32) -> Result<()> {
|
||||
use crate::daemon::rpc::grpc_defs::NetworkReorderRequest;
|
||||
|
||||
let mut client = BurrowClient::from_uds().await?;
|
||||
let reorder_request = NetworkReorderRequest { id, index };
|
||||
let res = client
|
||||
.networks_client
|
||||
.network_reorder(reorder_request)
|
||||
.await?;
|
||||
println!("Network Reorder Response: {:?}", res);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
async fn try_network_delete(id: i32) -> Result<()> {
|
||||
use crate::daemon::rpc::grpc_defs::NetworkDeleteRequest;
|
||||
|
||||
let mut client = BurrowClient::from_uds().await?;
|
||||
let delete_request = NetworkDeleteRequest { id };
|
||||
let res = client
|
||||
.networks_client
|
||||
.network_delete(delete_request)
|
||||
.await?;
|
||||
println!("Network Delete Response: {:?}", res);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -153,6 +277,14 @@ async fn main() -> Result<()> {
|
|||
Commands::ServerConfig => try_serverconfig().await?,
|
||||
Commands::ReloadConfig(args) => try_reloadconfig(args.interface_id.clone()).await?,
|
||||
Commands::AuthServer => crate::auth::server::serve().await?,
|
||||
Commands::ServerStatus => try_serverstatus().await?,
|
||||
Commands::TunnelConfig => try_tun_config().await?,
|
||||
Commands::NetworkAdd(args) => {
|
||||
try_network_add(args.id, args.network_type, &args.payload_path).await?
|
||||
}
|
||||
Commands::NetworkList => try_network_list().await?,
|
||||
Commands::NetworkReorder(args) => try_network_reorder(args.id, args.index).await?,
|
||||
Commands::NetworkDelete(args) => try_network_delete(args.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,17 +44,18 @@ 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>,
|
||||
pub listen_port: u32,
|
||||
pub listen_port: Option<u32>,
|
||||
pub dns: Vec<String>,
|
||||
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?
|
||||
}
|
||||
|
|
@ -98,7 +102,7 @@ impl Default for Config {
|
|||
interface: Interface {
|
||||
private_key: "OEPVdomeLTxTIBvv3TYsJRge0Hp9NMiY0sIrhT8OWG8=".into(),
|
||||
address: vec!["10.13.13.2/24".into()],
|
||||
listen_port: 51820,
|
||||
listen_port: Some(51820),
|
||||
dns: Default::default(),
|
||||
mtu: Default::default(),
|
||||
},
|
||||
|
|
@ -113,3 +117,83 @@ impl Default for Config {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn props_get<T>(props: &Properties, key: &str) -> Result<T>
|
||||
where
|
||||
T: TryFrom<IniField, Error = anyhow::Error>,
|
||||
{
|
||||
IniField::try_from(props.get(key))?.try_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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,6 +93,12 @@ impl Interface {
|
|||
*st = IfaceStatus::Running;
|
||||
}
|
||||
|
||||
pub async fn set_tun_ref(&mut self, tun: Arc<RwLock<Option<TunInterface>>>) {
|
||||
self.tun = tun;
|
||||
let mut st = self.status.write().await;
|
||||
*st = IfaceStatus::Running;
|
||||
}
|
||||
|
||||
pub fn get_tun(&self) -> Arc<RwLock<Option<TunInterface>>> {
|
||||
self.tun.clone()
|
||||
}
|
||||
|
|
@ -135,7 +141,7 @@ impl Interface {
|
|||
Some(addr) => addr,
|
||||
None => {
|
||||
debug!("No destination found");
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -154,7 +160,7 @@ impl Interface {
|
|||
}
|
||||
Err(e) => {
|
||||
log::error!("Failed to send packet {}", e);
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -175,7 +181,7 @@ impl Interface {
|
|||
let main_tsk = async move {
|
||||
if let Err(e) = pcb.open_if_closed().await {
|
||||
log::error!("failed to open pcb: {}", e);
|
||||
return
|
||||
return;
|
||||
}
|
||||
let r2 = pcb.run(tun).await;
|
||||
if let Err(e) = r2 {
|
||||
|
|
@ -195,7 +201,7 @@ impl Interface {
|
|||
Ok(..) => (),
|
||||
Err(e) => {
|
||||
error!("Failed to update timers: {}", e);
|
||||
return
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
81
burrow/src/wireguard/inifield.rs
Normal file
81
burrow/src/wireguard/inifield.rs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use anyhow::{Error, Result};
|
||||
|
||||
pub struct IniField(String);
|
||||
|
||||
impl FromStr for IniField {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(s.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IniField> for Vec<String> {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(field: IniField) -> Result<Self, Self::Error> {
|
||||
Ok(field.0.split(',').map(|s| s.trim().to_string()).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IniField> for u32 {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: IniField) -> Result<Self, Self::Error> {
|
||||
value.0.parse().map_err(Error::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IniField> for Option<u32> {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: IniField) -> Result<Self, Self::Error> {
|
||||
if value.0.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
value.0.parse().map(Some).map_err(Error::from)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IniField> for String {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: IniField) -> Result<Self, Self::Error> {
|
||||
Ok(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IniField> for Option<String> {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: IniField) -> Result<Self, Self::Error> {
|
||||
if value.0.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(value.0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TryFrom<Option<T>> for IniField
|
||||
where
|
||||
T: ToString,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: Option<T>) -> Result<Self, Self::Error> {
|
||||
Ok(match value {
|
||||
Some(v) => Self(v.to_string()),
|
||||
None => Self(String::new()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
---
|
||||
[[Peer]]
|
||||
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 = []
|
||||
|
||||
8
burrow/tmp/conrd.conf
Normal file
8
burrow/tmp/conrd.conf
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[Interface]
|
||||
PrivateKey = gAaK0KFGOpxY7geGo59XXDufcxeoSNXXNC12mCQmlVs=
|
||||
Address = 10.1.11.2/32
|
||||
DNS = 10.1.11.1
|
||||
[Peer]
|
||||
PublicKey = Ab6V2mgPHiCXaAZfQrNts8ha8RkEzC49VnmMQfe5Yg4=
|
||||
AllowedIPs = 10.1.11.1/32,10.1.11.2/32,0.0.0.0/0
|
||||
Endpoint = 172.251.163.175:51820
|
||||
|
|
@ -11,7 +11,7 @@ service Tunnel {
|
|||
}
|
||||
|
||||
service Networks {
|
||||
rpc NetworkAdd (Empty) returns (Empty);
|
||||
rpc NetworkAdd (Network) returns (Empty);
|
||||
rpc NetworkList (Empty) returns (stream NetworkListResponse);
|
||||
rpc NetworkReorder (NetworkReorderRequest) returns (Empty);
|
||||
rpc NetworkDelete (NetworkDeleteRequest) returns (Empty);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue