├── .github └── workflows │ └── release.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── flake.lock ├── flake.nix └── src ├── address.rs ├── asn.rs ├── config.rs ├── key.rs ├── lib.rs ├── main.rs ├── registry.rs └── vici.rs /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | on: [ push ] 3 | jobs: 4 | ranet-static: 5 | runs-on: ubuntu-latest 6 | strategy: 7 | matrix: 8 | target: 9 | - x86_64-unknown-linux-musl 10 | - aarch64-unknown-linux-musl 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: build 14 | run: | 15 | cargo install cross --git https://github.com/cross-rs/cross 16 | cross build --release --target ${{ matrix.target }} 17 | - uses: actions/upload-artifact@v4 18 | with: 19 | name: ${{ matrix.target }} 20 | path: target/${{ matrix.target }}/release/ranet 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.envrc 3 | /.direnv/ 4 | /result* 5 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "1.1.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "anstream" 31 | version = "0.6.18" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" 34 | dependencies = [ 35 | "anstyle", 36 | "anstyle-parse", 37 | "anstyle-query", 38 | "anstyle-wincon", 39 | "colorchoice", 40 | "is_terminal_polyfill", 41 | "utf8parse", 42 | ] 43 | 44 | [[package]] 45 | name = "anstyle" 46 | version = "1.0.10" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 49 | 50 | [[package]] 51 | name = "anstyle-parse" 52 | version = "0.2.6" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" 55 | dependencies = [ 56 | "utf8parse", 57 | ] 58 | 59 | [[package]] 60 | name = "anstyle-query" 61 | version = "1.1.2" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" 64 | dependencies = [ 65 | "windows-sys 0.59.0", 66 | ] 67 | 68 | [[package]] 69 | name = "anstyle-wincon" 70 | version = "3.0.7" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" 73 | dependencies = [ 74 | "anstyle", 75 | "once_cell", 76 | "windows-sys 0.59.0", 77 | ] 78 | 79 | [[package]] 80 | name = "async-stream" 81 | version = "0.3.6" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" 84 | dependencies = [ 85 | "async-stream-impl", 86 | "futures-core", 87 | "pin-project-lite", 88 | ] 89 | 90 | [[package]] 91 | name = "async-stream-impl" 92 | version = "0.3.6" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" 95 | dependencies = [ 96 | "proc-macro2", 97 | "quote 1.0.40", 98 | "syn 2.0.100", 99 | ] 100 | 101 | [[package]] 102 | name = "autocfg" 103 | version = "1.4.0" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 106 | 107 | [[package]] 108 | name = "backtrace" 109 | version = "0.3.74" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 112 | dependencies = [ 113 | "addr2line", 114 | "cfg-if", 115 | "libc", 116 | "miniz_oxide", 117 | "object", 118 | "rustc-demangle", 119 | "windows-targets", 120 | ] 121 | 122 | [[package]] 123 | name = "base64" 124 | version = "0.22.1" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 127 | 128 | [[package]] 129 | name = "base64ct" 130 | version = "1.7.3" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" 133 | 134 | [[package]] 135 | name = "block-buffer" 136 | version = "0.10.4" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 139 | dependencies = [ 140 | "generic-array", 141 | ] 142 | 143 | [[package]] 144 | name = "bytes" 145 | version = "1.10.1" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" 148 | 149 | [[package]] 150 | name = "cfg-if" 151 | version = "1.0.0" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 154 | 155 | [[package]] 156 | name = "clap" 157 | version = "4.5.32" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83" 160 | dependencies = [ 161 | "clap_builder", 162 | "clap_derive", 163 | ] 164 | 165 | [[package]] 166 | name = "clap_builder" 167 | version = "4.5.32" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8" 170 | dependencies = [ 171 | "anstream", 172 | "anstyle", 173 | "clap_lex", 174 | "strsim", 175 | ] 176 | 177 | [[package]] 178 | name = "clap_derive" 179 | version = "4.5.32" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" 182 | dependencies = [ 183 | "heck", 184 | "proc-macro2", 185 | "quote 1.0.40", 186 | "syn 2.0.100", 187 | ] 188 | 189 | [[package]] 190 | name = "clap_lex" 191 | version = "0.7.4" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" 194 | 195 | [[package]] 196 | name = "colorchoice" 197 | version = "1.0.3" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" 200 | 201 | [[package]] 202 | name = "const-oid" 203 | version = "0.9.6" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 206 | 207 | [[package]] 208 | name = "cpufeatures" 209 | version = "0.2.17" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 212 | dependencies = [ 213 | "libc", 214 | ] 215 | 216 | [[package]] 217 | name = "crypto-common" 218 | version = "0.1.6" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 221 | dependencies = [ 222 | "generic-array", 223 | "typenum", 224 | ] 225 | 226 | [[package]] 227 | name = "curve25519-dalek" 228 | version = "4.1.3" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" 231 | dependencies = [ 232 | "cfg-if", 233 | "cpufeatures", 234 | "curve25519-dalek-derive", 235 | "digest", 236 | "fiat-crypto", 237 | "rustc_version", 238 | "subtle", 239 | "zeroize", 240 | ] 241 | 242 | [[package]] 243 | name = "curve25519-dalek-derive" 244 | version = "0.1.1" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" 247 | dependencies = [ 248 | "proc-macro2", 249 | "quote 1.0.40", 250 | "syn 2.0.100", 251 | ] 252 | 253 | [[package]] 254 | name = "der" 255 | version = "0.7.9" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" 258 | dependencies = [ 259 | "const-oid", 260 | "der_derive", 261 | "flagset", 262 | "pem-rfc7468", 263 | "zeroize", 264 | ] 265 | 266 | [[package]] 267 | name = "der_derive" 268 | version = "0.7.3" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" 271 | dependencies = [ 272 | "proc-macro2", 273 | "quote 1.0.40", 274 | "syn 2.0.100", 275 | ] 276 | 277 | [[package]] 278 | name = "digest" 279 | version = "0.10.7" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 282 | dependencies = [ 283 | "block-buffer", 284 | "crypto-common", 285 | ] 286 | 287 | [[package]] 288 | name = "ed25519" 289 | version = "2.2.3" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" 292 | dependencies = [ 293 | "pkcs8", 294 | "signature", 295 | ] 296 | 297 | [[package]] 298 | name = "ed25519-dalek" 299 | version = "2.1.1" 300 | source = "registry+https://github.com/rust-lang/crates.io-index" 301 | checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" 302 | dependencies = [ 303 | "curve25519-dalek", 304 | "ed25519", 305 | "serde", 306 | "sha2", 307 | "subtle", 308 | "zeroize", 309 | ] 310 | 311 | [[package]] 312 | name = "enum_index" 313 | version = "0.2.0" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "f5532bdea562e7be83060c36185eecccba82fe16729d2eaad2891d65417656dd" 316 | 317 | [[package]] 318 | name = "enum_index_derive" 319 | version = "0.2.0" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "8ab22c8085548bf06190113dca556e149ecdbb05ae5b972a2b9899f26b944ee4" 322 | dependencies = [ 323 | "quote 0.3.15", 324 | "syn 0.11.11", 325 | ] 326 | 327 | [[package]] 328 | name = "equivalent" 329 | version = "1.0.2" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 332 | 333 | [[package]] 334 | name = "fiat-crypto" 335 | version = "0.2.9" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" 338 | 339 | [[package]] 340 | name = "flagset" 341 | version = "0.4.6" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" 344 | 345 | [[package]] 346 | name = "futures" 347 | version = "0.3.31" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 350 | dependencies = [ 351 | "futures-channel", 352 | "futures-core", 353 | "futures-executor", 354 | "futures-io", 355 | "futures-sink", 356 | "futures-task", 357 | "futures-util", 358 | ] 359 | 360 | [[package]] 361 | name = "futures-channel" 362 | version = "0.3.31" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 365 | dependencies = [ 366 | "futures-core", 367 | "futures-sink", 368 | ] 369 | 370 | [[package]] 371 | name = "futures-core" 372 | version = "0.3.31" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 375 | 376 | [[package]] 377 | name = "futures-executor" 378 | version = "0.3.31" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 381 | dependencies = [ 382 | "futures-core", 383 | "futures-task", 384 | "futures-util", 385 | ] 386 | 387 | [[package]] 388 | name = "futures-io" 389 | version = "0.3.31" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 392 | 393 | [[package]] 394 | name = "futures-macro" 395 | version = "0.3.31" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 398 | dependencies = [ 399 | "proc-macro2", 400 | "quote 1.0.40", 401 | "syn 2.0.100", 402 | ] 403 | 404 | [[package]] 405 | name = "futures-sink" 406 | version = "0.3.31" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 409 | 410 | [[package]] 411 | name = "futures-task" 412 | version = "0.3.31" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 415 | 416 | [[package]] 417 | name = "futures-util" 418 | version = "0.3.31" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 421 | dependencies = [ 422 | "futures-channel", 423 | "futures-core", 424 | "futures-io", 425 | "futures-macro", 426 | "futures-sink", 427 | "futures-task", 428 | "memchr", 429 | "pin-project-lite", 430 | "pin-utils", 431 | "slab", 432 | ] 433 | 434 | [[package]] 435 | name = "generic-array" 436 | version = "0.14.7" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 439 | dependencies = [ 440 | "typenum", 441 | "version_check", 442 | ] 443 | 444 | [[package]] 445 | name = "getrandom" 446 | version = "0.2.15" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 449 | dependencies = [ 450 | "cfg-if", 451 | "libc", 452 | "wasi", 453 | ] 454 | 455 | [[package]] 456 | name = "gimli" 457 | version = "0.31.1" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 460 | 461 | [[package]] 462 | name = "hashbrown" 463 | version = "0.15.2" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 466 | 467 | [[package]] 468 | name = "heck" 469 | version = "0.5.0" 470 | source = "registry+https://github.com/rust-lang/crates.io-index" 471 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 472 | 473 | [[package]] 474 | name = "hex" 475 | version = "0.4.3" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 478 | 479 | [[package]] 480 | name = "indexmap" 481 | version = "2.8.0" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" 484 | dependencies = [ 485 | "equivalent", 486 | "hashbrown", 487 | ] 488 | 489 | [[package]] 490 | name = "indoc" 491 | version = "2.0.6" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" 494 | 495 | [[package]] 496 | name = "ipnet" 497 | version = "2.11.0" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" 500 | 501 | [[package]] 502 | name = "is_terminal_polyfill" 503 | version = "1.70.1" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 506 | 507 | [[package]] 508 | name = "itoa" 509 | version = "1.0.15" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 512 | 513 | [[package]] 514 | name = "lazy_static" 515 | version = "1.5.0" 516 | source = "registry+https://github.com/rust-lang/crates.io-index" 517 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 518 | 519 | [[package]] 520 | name = "libc" 521 | version = "0.2.171" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" 524 | 525 | [[package]] 526 | name = "log" 527 | version = "0.4.26" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" 530 | 531 | [[package]] 532 | name = "matchers" 533 | version = "0.1.0" 534 | source = "registry+https://github.com/rust-lang/crates.io-index" 535 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 536 | dependencies = [ 537 | "regex-automata 0.1.10", 538 | ] 539 | 540 | [[package]] 541 | name = "memchr" 542 | version = "2.7.4" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 545 | 546 | [[package]] 547 | name = "miniz_oxide" 548 | version = "0.8.5" 549 | source = "registry+https://github.com/rust-lang/crates.io-index" 550 | checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" 551 | dependencies = [ 552 | "adler2", 553 | ] 554 | 555 | [[package]] 556 | name = "mio" 557 | version = "1.0.3" 558 | source = "registry+https://github.com/rust-lang/crates.io-index" 559 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 560 | dependencies = [ 561 | "libc", 562 | "wasi", 563 | "windows-sys 0.52.0", 564 | ] 565 | 566 | [[package]] 567 | name = "nu-ansi-term" 568 | version = "0.46.0" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 571 | dependencies = [ 572 | "overload", 573 | "winapi", 574 | ] 575 | 576 | [[package]] 577 | name = "num_enum" 578 | version = "0.5.11" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" 581 | dependencies = [ 582 | "num_enum_derive", 583 | ] 584 | 585 | [[package]] 586 | name = "num_enum_derive" 587 | version = "0.5.11" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" 590 | dependencies = [ 591 | "proc-macro-crate", 592 | "proc-macro2", 593 | "quote 1.0.40", 594 | "syn 1.0.109", 595 | ] 596 | 597 | [[package]] 598 | name = "object" 599 | version = "0.36.7" 600 | source = "registry+https://github.com/rust-lang/crates.io-index" 601 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 602 | dependencies = [ 603 | "memchr", 604 | ] 605 | 606 | [[package]] 607 | name = "once_cell" 608 | version = "1.21.1" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" 611 | 612 | [[package]] 613 | name = "overload" 614 | version = "0.1.1" 615 | source = "registry+https://github.com/rust-lang/crates.io-index" 616 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 617 | 618 | [[package]] 619 | name = "pem-rfc7468" 620 | version = "0.7.0" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" 623 | dependencies = [ 624 | "base64ct", 625 | ] 626 | 627 | [[package]] 628 | name = "pin-project-lite" 629 | version = "0.2.16" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 632 | 633 | [[package]] 634 | name = "pin-utils" 635 | version = "0.1.0" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 638 | 639 | [[package]] 640 | name = "pkcs8" 641 | version = "0.10.2" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" 644 | dependencies = [ 645 | "der", 646 | "spki", 647 | ] 648 | 649 | [[package]] 650 | name = "proc-macro-crate" 651 | version = "1.3.1" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" 654 | dependencies = [ 655 | "once_cell", 656 | "toml_edit", 657 | ] 658 | 659 | [[package]] 660 | name = "proc-macro2" 661 | version = "1.0.94" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" 664 | dependencies = [ 665 | "unicode-ident", 666 | ] 667 | 668 | [[package]] 669 | name = "quote" 670 | version = "0.3.15" 671 | source = "registry+https://github.com/rust-lang/crates.io-index" 672 | checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" 673 | 674 | [[package]] 675 | name = "quote" 676 | version = "1.0.40" 677 | source = "registry+https://github.com/rust-lang/crates.io-index" 678 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 679 | dependencies = [ 680 | "proc-macro2", 681 | ] 682 | 683 | [[package]] 684 | name = "rand_core" 685 | version = "0.6.4" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 688 | dependencies = [ 689 | "getrandom", 690 | ] 691 | 692 | [[package]] 693 | name = "ranet" 694 | version = "0.12.0" 695 | dependencies = [ 696 | "base64", 697 | "clap", 698 | "const-oid", 699 | "ed25519-dalek", 700 | "futures", 701 | "hex", 702 | "indoc", 703 | "ipnet", 704 | "rsvici", 705 | "semver", 706 | "serde", 707 | "serde_json", 708 | "sha2", 709 | "thiserror", 710 | "tokio", 711 | "tracing", 712 | "tracing-subscriber", 713 | "x509-cert", 714 | ] 715 | 716 | [[package]] 717 | name = "regex" 718 | version = "1.11.1" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 721 | dependencies = [ 722 | "aho-corasick", 723 | "memchr", 724 | "regex-automata 0.4.9", 725 | "regex-syntax 0.8.5", 726 | ] 727 | 728 | [[package]] 729 | name = "regex-automata" 730 | version = "0.1.10" 731 | source = "registry+https://github.com/rust-lang/crates.io-index" 732 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 733 | dependencies = [ 734 | "regex-syntax 0.6.29", 735 | ] 736 | 737 | [[package]] 738 | name = "regex-automata" 739 | version = "0.4.9" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 742 | dependencies = [ 743 | "aho-corasick", 744 | "memchr", 745 | "regex-syntax 0.8.5", 746 | ] 747 | 748 | [[package]] 749 | name = "regex-syntax" 750 | version = "0.6.29" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 753 | 754 | [[package]] 755 | name = "regex-syntax" 756 | version = "0.8.5" 757 | source = "registry+https://github.com/rust-lang/crates.io-index" 758 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 759 | 760 | [[package]] 761 | name = "rsvici" 762 | version = "0.1.1" 763 | source = "registry+https://github.com/rust-lang/crates.io-index" 764 | checksum = "f872868b8bf48719a0a71d464a95df44a8672bf1cba963aabcc1d9a640e527d4" 765 | dependencies = [ 766 | "async-stream", 767 | "bytes", 768 | "enum_index", 769 | "enum_index_derive", 770 | "futures-util", 771 | "serde", 772 | "serde_vici", 773 | "tokio", 774 | "tokio-stream", 775 | ] 776 | 777 | [[package]] 778 | name = "rustc-demangle" 779 | version = "0.1.24" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 782 | 783 | [[package]] 784 | name = "rustc_version" 785 | version = "0.4.1" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" 788 | dependencies = [ 789 | "semver", 790 | ] 791 | 792 | [[package]] 793 | name = "ryu" 794 | version = "1.0.20" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 797 | 798 | [[package]] 799 | name = "semver" 800 | version = "1.0.26" 801 | source = "registry+https://github.com/rust-lang/crates.io-index" 802 | checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" 803 | 804 | [[package]] 805 | name = "serde" 806 | version = "1.0.219" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 809 | dependencies = [ 810 | "serde_derive", 811 | ] 812 | 813 | [[package]] 814 | name = "serde_derive" 815 | version = "1.0.219" 816 | source = "registry+https://github.com/rust-lang/crates.io-index" 817 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 818 | dependencies = [ 819 | "proc-macro2", 820 | "quote 1.0.40", 821 | "syn 2.0.100", 822 | ] 823 | 824 | [[package]] 825 | name = "serde_json" 826 | version = "1.0.140" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 829 | dependencies = [ 830 | "itoa", 831 | "memchr", 832 | "ryu", 833 | "serde", 834 | ] 835 | 836 | [[package]] 837 | name = "serde_vici" 838 | version = "0.1.3" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "ec58a4341fcc846c8d1665a4eead0185129805a750162eaee5b35909b3086036" 841 | dependencies = [ 842 | "bytes", 843 | "itoa", 844 | "num_enum", 845 | "ryu", 846 | "serde", 847 | ] 848 | 849 | [[package]] 850 | name = "sha2" 851 | version = "0.10.8" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 854 | dependencies = [ 855 | "cfg-if", 856 | "cpufeatures", 857 | "digest", 858 | ] 859 | 860 | [[package]] 861 | name = "sharded-slab" 862 | version = "0.1.7" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 865 | dependencies = [ 866 | "lazy_static", 867 | ] 868 | 869 | [[package]] 870 | name = "signature" 871 | version = "2.2.0" 872 | source = "registry+https://github.com/rust-lang/crates.io-index" 873 | checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" 874 | dependencies = [ 875 | "rand_core", 876 | ] 877 | 878 | [[package]] 879 | name = "slab" 880 | version = "0.4.9" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 883 | dependencies = [ 884 | "autocfg", 885 | ] 886 | 887 | [[package]] 888 | name = "smallvec" 889 | version = "1.14.0" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" 892 | 893 | [[package]] 894 | name = "socket2" 895 | version = "0.5.8" 896 | source = "registry+https://github.com/rust-lang/crates.io-index" 897 | checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" 898 | dependencies = [ 899 | "libc", 900 | "windows-sys 0.52.0", 901 | ] 902 | 903 | [[package]] 904 | name = "spki" 905 | version = "0.7.3" 906 | source = "registry+https://github.com/rust-lang/crates.io-index" 907 | checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" 908 | dependencies = [ 909 | "base64ct", 910 | "der", 911 | ] 912 | 913 | [[package]] 914 | name = "strsim" 915 | version = "0.11.1" 916 | source = "registry+https://github.com/rust-lang/crates.io-index" 917 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 918 | 919 | [[package]] 920 | name = "subtle" 921 | version = "2.6.1" 922 | source = "registry+https://github.com/rust-lang/crates.io-index" 923 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 924 | 925 | [[package]] 926 | name = "syn" 927 | version = "0.11.11" 928 | source = "registry+https://github.com/rust-lang/crates.io-index" 929 | checksum = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" 930 | dependencies = [ 931 | "quote 0.3.15", 932 | "synom", 933 | "unicode-xid", 934 | ] 935 | 936 | [[package]] 937 | name = "syn" 938 | version = "1.0.109" 939 | source = "registry+https://github.com/rust-lang/crates.io-index" 940 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 941 | dependencies = [ 942 | "proc-macro2", 943 | "quote 1.0.40", 944 | "unicode-ident", 945 | ] 946 | 947 | [[package]] 948 | name = "syn" 949 | version = "2.0.100" 950 | source = "registry+https://github.com/rust-lang/crates.io-index" 951 | checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" 952 | dependencies = [ 953 | "proc-macro2", 954 | "quote 1.0.40", 955 | "unicode-ident", 956 | ] 957 | 958 | [[package]] 959 | name = "synom" 960 | version = "0.11.3" 961 | source = "registry+https://github.com/rust-lang/crates.io-index" 962 | checksum = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" 963 | dependencies = [ 964 | "unicode-xid", 965 | ] 966 | 967 | [[package]] 968 | name = "thiserror" 969 | version = "2.0.12" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" 972 | dependencies = [ 973 | "thiserror-impl", 974 | ] 975 | 976 | [[package]] 977 | name = "thiserror-impl" 978 | version = "2.0.12" 979 | source = "registry+https://github.com/rust-lang/crates.io-index" 980 | checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" 981 | dependencies = [ 982 | "proc-macro2", 983 | "quote 1.0.40", 984 | "syn 2.0.100", 985 | ] 986 | 987 | [[package]] 988 | name = "thread_local" 989 | version = "1.1.8" 990 | source = "registry+https://github.com/rust-lang/crates.io-index" 991 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 992 | dependencies = [ 993 | "cfg-if", 994 | "once_cell", 995 | ] 996 | 997 | [[package]] 998 | name = "tls_codec" 999 | version = "0.4.2" 1000 | source = "registry+https://github.com/rust-lang/crates.io-index" 1001 | checksum = "0de2e01245e2bb89d6f05801c564fa27624dbd7b1846859876c7dad82e90bf6b" 1002 | dependencies = [ 1003 | "tls_codec_derive", 1004 | "zeroize", 1005 | ] 1006 | 1007 | [[package]] 1008 | name = "tls_codec_derive" 1009 | version = "0.4.2" 1010 | source = "registry+https://github.com/rust-lang/crates.io-index" 1011 | checksum = "2d2e76690929402faae40aebdda620a2c0e25dd6d3b9afe48867dfd95991f4bd" 1012 | dependencies = [ 1013 | "proc-macro2", 1014 | "quote 1.0.40", 1015 | "syn 2.0.100", 1016 | ] 1017 | 1018 | [[package]] 1019 | name = "tokio" 1020 | version = "1.44.1" 1021 | source = "registry+https://github.com/rust-lang/crates.io-index" 1022 | checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" 1023 | dependencies = [ 1024 | "backtrace", 1025 | "bytes", 1026 | "libc", 1027 | "mio", 1028 | "pin-project-lite", 1029 | "socket2", 1030 | "tokio-macros", 1031 | "windows-sys 0.52.0", 1032 | ] 1033 | 1034 | [[package]] 1035 | name = "tokio-macros" 1036 | version = "2.5.0" 1037 | source = "registry+https://github.com/rust-lang/crates.io-index" 1038 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 1039 | dependencies = [ 1040 | "proc-macro2", 1041 | "quote 1.0.40", 1042 | "syn 2.0.100", 1043 | ] 1044 | 1045 | [[package]] 1046 | name = "tokio-stream" 1047 | version = "0.1.17" 1048 | source = "registry+https://github.com/rust-lang/crates.io-index" 1049 | checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" 1050 | dependencies = [ 1051 | "futures-core", 1052 | "pin-project-lite", 1053 | "tokio", 1054 | ] 1055 | 1056 | [[package]] 1057 | name = "toml_datetime" 1058 | version = "0.6.8" 1059 | source = "registry+https://github.com/rust-lang/crates.io-index" 1060 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 1061 | 1062 | [[package]] 1063 | name = "toml_edit" 1064 | version = "0.19.15" 1065 | source = "registry+https://github.com/rust-lang/crates.io-index" 1066 | checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" 1067 | dependencies = [ 1068 | "indexmap", 1069 | "toml_datetime", 1070 | "winnow", 1071 | ] 1072 | 1073 | [[package]] 1074 | name = "tracing" 1075 | version = "0.1.41" 1076 | source = "registry+https://github.com/rust-lang/crates.io-index" 1077 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 1078 | dependencies = [ 1079 | "pin-project-lite", 1080 | "tracing-attributes", 1081 | "tracing-core", 1082 | ] 1083 | 1084 | [[package]] 1085 | name = "tracing-attributes" 1086 | version = "0.1.28" 1087 | source = "registry+https://github.com/rust-lang/crates.io-index" 1088 | checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" 1089 | dependencies = [ 1090 | "proc-macro2", 1091 | "quote 1.0.40", 1092 | "syn 2.0.100", 1093 | ] 1094 | 1095 | [[package]] 1096 | name = "tracing-core" 1097 | version = "0.1.33" 1098 | source = "registry+https://github.com/rust-lang/crates.io-index" 1099 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 1100 | dependencies = [ 1101 | "once_cell", 1102 | "valuable", 1103 | ] 1104 | 1105 | [[package]] 1106 | name = "tracing-log" 1107 | version = "0.2.0" 1108 | source = "registry+https://github.com/rust-lang/crates.io-index" 1109 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 1110 | dependencies = [ 1111 | "log", 1112 | "once_cell", 1113 | "tracing-core", 1114 | ] 1115 | 1116 | [[package]] 1117 | name = "tracing-subscriber" 1118 | version = "0.3.19" 1119 | source = "registry+https://github.com/rust-lang/crates.io-index" 1120 | checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" 1121 | dependencies = [ 1122 | "matchers", 1123 | "nu-ansi-term", 1124 | "once_cell", 1125 | "regex", 1126 | "sharded-slab", 1127 | "smallvec", 1128 | "thread_local", 1129 | "tracing", 1130 | "tracing-core", 1131 | "tracing-log", 1132 | ] 1133 | 1134 | [[package]] 1135 | name = "typenum" 1136 | version = "1.18.0" 1137 | source = "registry+https://github.com/rust-lang/crates.io-index" 1138 | checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" 1139 | 1140 | [[package]] 1141 | name = "unicode-ident" 1142 | version = "1.0.18" 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" 1144 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 1145 | 1146 | [[package]] 1147 | name = "unicode-xid" 1148 | version = "0.0.4" 1149 | source = "registry+https://github.com/rust-lang/crates.io-index" 1150 | checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" 1151 | 1152 | [[package]] 1153 | name = "utf8parse" 1154 | version = "0.2.2" 1155 | source = "registry+https://github.com/rust-lang/crates.io-index" 1156 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 1157 | 1158 | [[package]] 1159 | name = "valuable" 1160 | version = "0.1.1" 1161 | source = "registry+https://github.com/rust-lang/crates.io-index" 1162 | checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 1163 | 1164 | [[package]] 1165 | name = "version_check" 1166 | version = "0.9.5" 1167 | source = "registry+https://github.com/rust-lang/crates.io-index" 1168 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1169 | 1170 | [[package]] 1171 | name = "wasi" 1172 | version = "0.11.0+wasi-snapshot-preview1" 1173 | source = "registry+https://github.com/rust-lang/crates.io-index" 1174 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1175 | 1176 | [[package]] 1177 | name = "winapi" 1178 | version = "0.3.9" 1179 | source = "registry+https://github.com/rust-lang/crates.io-index" 1180 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1181 | dependencies = [ 1182 | "winapi-i686-pc-windows-gnu", 1183 | "winapi-x86_64-pc-windows-gnu", 1184 | ] 1185 | 1186 | [[package]] 1187 | name = "winapi-i686-pc-windows-gnu" 1188 | version = "0.4.0" 1189 | source = "registry+https://github.com/rust-lang/crates.io-index" 1190 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1191 | 1192 | [[package]] 1193 | name = "winapi-x86_64-pc-windows-gnu" 1194 | version = "0.4.0" 1195 | source = "registry+https://github.com/rust-lang/crates.io-index" 1196 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1197 | 1198 | [[package]] 1199 | name = "windows-sys" 1200 | version = "0.52.0" 1201 | source = "registry+https://github.com/rust-lang/crates.io-index" 1202 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1203 | dependencies = [ 1204 | "windows-targets", 1205 | ] 1206 | 1207 | [[package]] 1208 | name = "windows-sys" 1209 | version = "0.59.0" 1210 | source = "registry+https://github.com/rust-lang/crates.io-index" 1211 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1212 | dependencies = [ 1213 | "windows-targets", 1214 | ] 1215 | 1216 | [[package]] 1217 | name = "windows-targets" 1218 | version = "0.52.6" 1219 | source = "registry+https://github.com/rust-lang/crates.io-index" 1220 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1221 | dependencies = [ 1222 | "windows_aarch64_gnullvm", 1223 | "windows_aarch64_msvc", 1224 | "windows_i686_gnu", 1225 | "windows_i686_gnullvm", 1226 | "windows_i686_msvc", 1227 | "windows_x86_64_gnu", 1228 | "windows_x86_64_gnullvm", 1229 | "windows_x86_64_msvc", 1230 | ] 1231 | 1232 | [[package]] 1233 | name = "windows_aarch64_gnullvm" 1234 | version = "0.52.6" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1237 | 1238 | [[package]] 1239 | name = "windows_aarch64_msvc" 1240 | version = "0.52.6" 1241 | source = "registry+https://github.com/rust-lang/crates.io-index" 1242 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1243 | 1244 | [[package]] 1245 | name = "windows_i686_gnu" 1246 | version = "0.52.6" 1247 | source = "registry+https://github.com/rust-lang/crates.io-index" 1248 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1249 | 1250 | [[package]] 1251 | name = "windows_i686_gnullvm" 1252 | version = "0.52.6" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1255 | 1256 | [[package]] 1257 | name = "windows_i686_msvc" 1258 | version = "0.52.6" 1259 | source = "registry+https://github.com/rust-lang/crates.io-index" 1260 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1261 | 1262 | [[package]] 1263 | name = "windows_x86_64_gnu" 1264 | version = "0.52.6" 1265 | source = "registry+https://github.com/rust-lang/crates.io-index" 1266 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1267 | 1268 | [[package]] 1269 | name = "windows_x86_64_gnullvm" 1270 | version = "0.52.6" 1271 | source = "registry+https://github.com/rust-lang/crates.io-index" 1272 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1273 | 1274 | [[package]] 1275 | name = "windows_x86_64_msvc" 1276 | version = "0.52.6" 1277 | source = "registry+https://github.com/rust-lang/crates.io-index" 1278 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1279 | 1280 | [[package]] 1281 | name = "winnow" 1282 | version = "0.5.40" 1283 | source = "registry+https://github.com/rust-lang/crates.io-index" 1284 | checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" 1285 | dependencies = [ 1286 | "memchr", 1287 | ] 1288 | 1289 | [[package]] 1290 | name = "x509-cert" 1291 | version = "0.2.5" 1292 | source = "registry+https://github.com/rust-lang/crates.io-index" 1293 | checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94" 1294 | dependencies = [ 1295 | "const-oid", 1296 | "der", 1297 | "spki", 1298 | "tls_codec", 1299 | ] 1300 | 1301 | [[package]] 1302 | name = "zeroize" 1303 | version = "1.8.1" 1304 | source = "registry+https://github.com/rust-lang/crates.io-index" 1305 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 1306 | dependencies = [ 1307 | "zeroize_derive", 1308 | ] 1309 | 1310 | [[package]] 1311 | name = "zeroize_derive" 1312 | version = "1.4.2" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" 1315 | dependencies = [ 1316 | "proc-macro2", 1317 | "quote 1.0.40", 1318 | "syn 2.0.100", 1319 | ] 1320 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ranet" 3 | version = "0.12.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | tokio = { version = "1", features = [ "macros", "rt-multi-thread", "fs" ] } 8 | serde = { version = "1", features = [ "derive" ] } 9 | serde_json = "1" 10 | rsvici = "*" 11 | clap = { version = "4", features = ["derive"] } 12 | hex = "*" 13 | ipnet = "*" 14 | semver = "*" 15 | thiserror = "*" 16 | indoc = "*" 17 | tracing = { version = "*" } 18 | tracing-subscriber = { version = "*", features = [ "env-filter" ] } 19 | futures = "*" 20 | const-oid = { version = "0.9.6", features = ["db"] } 21 | x509-cert = "0.2.5" 22 | ed25519-dalek = { version = "2.1.1", features = ["pkcs8", "pem"] } 23 | sha2 = "0.10.8" 24 | base64 = "0.22.1" 25 | 26 | [profile.release] 27 | lto = true 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 SCP-2000 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ranet - redundant array of networks 2 | 3 | #### About 4 | 5 | ranet, acronym for redundant array of networks, forms full mesh IPSec connectivity among network participants. 6 | 7 | #### Configuration 8 | 9 | ```json5 10 | { 11 | "organization": "acme corp", // unique identifier of a keypair 12 | "common_name": "some server", // node name, unique within an organization 13 | "endpoints": [ 14 | { 15 | "serial_number": "0", // fort distinguishing endpoints, unique within a node 16 | "address": "1.1.1.1", // ip address or cidr, can be omitted 17 | "address_family": "ip4", // or ip6 18 | "port": 13000, // must be identical to charon.port_nat_t 19 | "updown": "/usr/local/bin/updown", // script to run on connection changes, see https://docs.strongswan.org/docs/5.9/plugins/updown.html 20 | "fwmark": null // see .set_mark_out in https://docs.strongswan.org/docs/5.9/swanctl/swanctlConf.html 21 | }, 22 | { 23 | "serial_number": "1", 24 | "address": null, 25 | "address_family": "ip6", 26 | "port": 13000, 27 | "updown": "/usr/local/bin/updown", 28 | "fwmark": null 29 | } 30 | ] 31 | } 32 | ``` 33 | 34 | #### Registry 35 | 36 | The registry is a json array containing information of mesh participants. 37 | ```json5 38 | [ 39 | { 40 | "public_key": "", 41 | "organization": "acme corp", 42 | "nodes": [ 43 | { 44 | "common_name": "some server", 45 | "endpoints": [ 46 | { 47 | "serial_number": "0", // matches one-to-one with endpoints in local config 48 | "address_family": "ip4", 49 | "address": "example.com", // ip or domain name, can be omitted 50 | "port": 13000 51 | }, 52 | { 53 | "serial_number": "1", 54 | "address_family": "ip6", 55 | "address": null, 56 | "port": 13000 57 | } 58 | ], 59 | "remarks": { 60 | "arbitrary": "metadata" 61 | } 62 | } 63 | ] 64 | } 65 | ] 66 | ``` 67 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1731533236, 9 | "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1748351987, 24 | "narHash": "sha256-6ZEAzUR8fupWrvFfEKo42zrWBvumQ9Sfd/2qpVA8WqQ=", 25 | "owner": "NickCao", 26 | "repo": "nixpkgs", 27 | "rev": "b812fc8a74c3b53c8cec5e66d8a689f84191d6c1", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "NickCao", 32 | "repo": "nixpkgs", 33 | "type": "github" 34 | } 35 | }, 36 | "root": { 37 | "inputs": { 38 | "flake-utils": "flake-utils", 39 | "nixpkgs": "nixpkgs" 40 | } 41 | }, 42 | "systems": { 43 | "locked": { 44 | "lastModified": 1681028828, 45 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 46 | "owner": "nix-systems", 47 | "repo": "default", 48 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 49 | "type": "github" 50 | }, 51 | "original": { 52 | "owner": "nix-systems", 53 | "repo": "default", 54 | "type": "github" 55 | } 56 | } 57 | }, 58 | "root": "root", 59 | "version": 7 60 | } 61 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | nixpkgs.url = "github:NickCao/nixpkgs"; 4 | flake-utils.url = "github:numtide/flake-utils"; 5 | }; 6 | outputs = { self, nixpkgs, flake-utils }: 7 | flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] 8 | (system: 9 | let 10 | pkgs = import nixpkgs { 11 | inherit system; 12 | overlays = [ self.overlays.default ]; 13 | }; 14 | in 15 | rec { 16 | packages = { 17 | default = pkgs.ranet; 18 | ranet = pkgs.ranet; 19 | ranet-static = pkgs.pkgsStatic.ranet; 20 | }; 21 | devShells.default = pkgs.mkShell { 22 | nativeBuildInputs = with pkgs;[ rustfmt rust-analyzer ]; 23 | inputsFrom = [ packages.default ]; 24 | }; 25 | } 26 | ) // { 27 | overlays.default = final: _: with final; { 28 | ranet = rustPlatform.buildRustPackage { 29 | name = "ranet"; 30 | src = self; 31 | cargoLock = { 32 | lockFile = ./Cargo.lock; 33 | }; 34 | checkFlags = [ "--skip=address::test::remote" ]; 35 | }; 36 | }; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /src/address.rs: -------------------------------------------------------------------------------- 1 | use ipnet::IpNet; 2 | use std::net::IpAddr; 3 | use std::net::ToSocketAddrs; 4 | use std::str::FromStr; 5 | 6 | pub fn local(address_family: &str, address: &Option) -> Vec { 7 | if let Some(address) = address { 8 | if let Ok(address) = IpAddr::from_str(address) { 9 | // TODO: check if address family matches 10 | return vec![address.to_string()]; 11 | } 12 | if let Ok(cidr) = IpNet::from_str(address) { 13 | // TODO: check if address family matches 14 | return vec![cidr.to_string()]; 15 | } 16 | vec![] 17 | } else { 18 | match address_family { 19 | "ip4" => vec!["0.0.0.0/0".to_string()], 20 | "ip6" => vec!["::/0".to_string()], 21 | _ => vec![], 22 | } 23 | } 24 | } 25 | 26 | pub fn remote(address_family: &str, address: &Option) -> Vec { 27 | let mut addresses = match address_family { 28 | "ip4" => vec!["0.0.0.0/0".to_string()], 29 | "ip6" => vec!["::/0".to_string()], 30 | _ => vec![], 31 | }; 32 | 33 | if let Some(address) = address { 34 | if let Some(address) = (address.as_str(), 0) 35 | .to_socket_addrs() 36 | .unwrap_or_else(|_| vec![].into_iter()) 37 | .find(|addr| match address_family { 38 | "ip4" => addr.is_ipv4(), 39 | "ip6" => addr.is_ipv6(), 40 | _ => false, 41 | }) 42 | .map(|addr| addr.ip().to_string()) 43 | { 44 | addresses.push(address); 45 | } 46 | } 47 | 48 | addresses 49 | } 50 | 51 | #[cfg(test)] 52 | mod test { 53 | #[test] 54 | fn local() { 55 | assert_eq!(super::local("invalid", &None), Vec::::new()); 56 | assert_eq!(super::local("ip4", &None), vec!["0.0.0.0/0"]); 57 | assert_eq!(super::local("ip6", &None), vec!["::/0"]); 58 | assert_eq!( 59 | super::local("ip4", &Some("127.0.0.1".to_string())), 60 | vec!["127.0.0.1"] 61 | ); 62 | assert_eq!(super::local("ip6", &Some("::1".to_string())), vec!["::1"]); 63 | assert_eq!( 64 | super::local("ip4", &Some("10.0.0.0/24".to_string())), 65 | vec!["10.0.0.0/24"] 66 | ); 67 | assert_eq!( 68 | super::local("ip6", &Some("fd00::/8".to_string())), 69 | vec!["fd00::/8"] 70 | ); 71 | } 72 | 73 | #[test] 74 | fn remote() { 75 | assert_eq!(super::remote("invalid", &None), Vec::::new()); 76 | assert_eq!(super::remote("ip4", &None), vec!["0.0.0.0/0".to_string()]); 77 | assert_eq!(super::remote("ip6", &None), vec!["::/0".to_string()]); 78 | assert_eq!( 79 | super::remote("ip4", &Some("name.invalid".to_string())), 80 | vec!["0.0.0.0/0".to_string()] 81 | ); 82 | assert_eq!( 83 | super::remote("ip6", &Some("name.invalid".to_string())), 84 | vec!["::/0".to_string()] 85 | ); 86 | assert_eq!( 87 | super::remote("ip4", &Some("localhost".to_string())), 88 | vec!["0.0.0.0/0".to_string(), "127.0.0.1".to_string()] 89 | ); 90 | assert_eq!( 91 | super::remote("ip6", &Some("localhost".to_string())), 92 | vec!["::/0".to_string(), "::1".to_string()] 93 | ); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/asn.rs: -------------------------------------------------------------------------------- 1 | use const_oid::db::rfc4519::{CN, ORGANIZATION_NAME, SERIAL_NUMBER}; 2 | use x509_cert::{ 3 | attr::AttributeTypeAndValue, 4 | der::asn1::{PrintableString, SetOfVec, Utf8StringRef}, 5 | der::{Encode, Result}, 6 | name::{RdnSequence, RelativeDistinguishedName}, 7 | }; 8 | 9 | pub fn encode_identity( 10 | organization: &str, 11 | common_name: &str, 12 | serial_number: &str, 13 | ) -> Result { 14 | let name = RdnSequence(vec![ 15 | RelativeDistinguishedName(SetOfVec::from_iter([AttributeTypeAndValue { 16 | oid: ORGANIZATION_NAME, 17 | value: Utf8StringRef::new(organization)?.into(), 18 | }])?), 19 | RelativeDistinguishedName(SetOfVec::from_iter([AttributeTypeAndValue { 20 | oid: CN, 21 | value: Utf8StringRef::new(common_name)?.into(), 22 | }])?), 23 | RelativeDistinguishedName(SetOfVec::from_iter([AttributeTypeAndValue { 24 | oid: SERIAL_NUMBER, 25 | value: (&PrintableString::new(serial_number)?).into(), 26 | }])?), 27 | ]) 28 | .to_der()?; 29 | Ok(format!("asn1dn:#{}", hex::encode(name))) 30 | } 31 | 32 | #[cfg(test)] 33 | mod test { 34 | #[test] 35 | fn encode_identity() { 36 | let identity = super::encode_identity("acme organization", "some server", "0").unwrap(); 37 | assert_eq!( 38 | identity, 39 | "asn1dn:#303e311a3018060355040a0c1161636d65206f7267616e697a6174696f6e3114301206035504030c0b736f6d6520736572766572310a30080603550405130130", 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | #[derive(Debug, Deserialize, Serialize, PartialEq)] 4 | #[serde(deny_unknown_fields)] 5 | pub struct Config { 6 | pub organization: String, 7 | pub common_name: String, 8 | pub endpoints: Vec, 9 | } 10 | 11 | #[derive(Debug, Deserialize, Serialize, PartialEq)] 12 | #[serde(deny_unknown_fields)] 13 | pub struct Endpoint { 14 | pub serial_number: String, 15 | pub address_family: String, 16 | pub address: Option, 17 | pub port: u16, 18 | 19 | pub updown: Option, 20 | pub fwmark: Option, 21 | } 22 | -------------------------------------------------------------------------------- /src/key.rs: -------------------------------------------------------------------------------- 1 | use ed25519_dalek::{ 2 | pkcs8::{DecodePrivateKey, EncodePublicKey, Error}, 3 | SigningKey, 4 | }; 5 | use x509_cert::der::pem::LineEnding; 6 | 7 | pub fn private_key_to_public(pem: &str) -> Result { 8 | Ok(SigningKey::from_pkcs8_pem(pem)? 9 | .verifying_key() 10 | .to_public_key_pem(LineEnding::LF)?) 11 | } 12 | 13 | #[cfg(test)] 14 | mod test { 15 | use indoc::indoc; 16 | 17 | #[test] 18 | fn private_key_to_public() { 19 | let private_key = indoc! {" 20 | -----BEGIN PRIVATE KEY----- 21 | MC4CAQAwBQYDK2VwBCIEIHJiQXiRUBti6HjAxgz3p2ZwIJNjPT/P5iuYPYLhOylO 22 | -----END PRIVATE KEY----- 23 | "}; 24 | 25 | let public_key = super::private_key_to_public(private_key).unwrap(); 26 | 27 | assert_eq!( 28 | public_key, 29 | indoc! {" 30 | -----BEGIN PUBLIC KEY----- 31 | MCowBQYDK2VwAyEA29QaBk/rDPEAeC0nkc4agVCCCPh+D5eco9NoEX4CljU= 32 | -----END PUBLIC KEY----- 33 | "} 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use base64::prelude::{Engine, BASE64_URL_SAFE}; 2 | use config::Config; 3 | use core::str; 4 | use registry::Registry; 5 | use sha2::{Digest, Sha256}; 6 | use std::collections::HashSet; 7 | use tracing::{debug, debug_span, info, warn}; 8 | 9 | pub mod address; 10 | pub mod asn; 11 | pub mod config; 12 | pub mod key; 13 | pub mod registry; 14 | pub mod vici; 15 | 16 | pub mod error { 17 | use std::{str::Utf8Error, string::FromUtf8Error}; 18 | use thiserror::Error; 19 | 20 | #[derive(Debug, Error)] 21 | pub enum Error { 22 | #[error("io error")] 23 | IO(#[from] std::io::Error), 24 | #[error("vici error")] 25 | Vici(#[from] rsvici::Error), 26 | #[error("semver error")] 27 | Semver(#[from] semver::Error), 28 | #[error("protocol error: {0:?}")] 29 | Protocol(Option), 30 | #[error("from utf8 error")] 31 | FromUtf8(#[from] FromUtf8Error), 32 | #[error("utf8 error")] 33 | Utf8(#[from] Utf8Error), 34 | #[error("pkcs8 error")] 35 | Openssl(#[from] ed25519_dalek::pkcs8::Error), 36 | #[error("serde json error")] 37 | Json(#[from] serde_json::Error), 38 | } 39 | } 40 | 41 | fn generate_name(existing: &HashSet, data: &[u8]) -> String { 42 | let mut data = data.to_vec(); 43 | loop { 44 | let name = BASE64_URL_SAFE.encode(&Sha256::digest(&data)[..3]); 45 | if existing.contains(&name) { 46 | data.push(0); 47 | } else { 48 | return name; 49 | } 50 | } 51 | } 52 | 53 | pub async fn reconcile( 54 | socket: &str, 55 | config: &Config, 56 | registry: &Registry, 57 | key: &[u8], 58 | ) -> Result<(), error::Error> { 59 | let _span_reconcile = debug_span!("reconcile").entered(); 60 | 61 | let mut client = vici::Client::connect(socket).await?; 62 | 63 | debug!("connected to vici socket"); 64 | 65 | client.load_key(key).await?; 66 | 67 | debug!("loaded private key"); 68 | 69 | let public_key = key::private_key_to_public(str::from_utf8(key)?)?; 70 | 71 | debug!("derived public key"); 72 | 73 | let mut desired = HashSet::::default(); 74 | 75 | for local in &config.endpoints { 76 | let _span_local = debug_span!("local").entered(); 77 | 78 | let local_id = asn::encode_identity( 79 | &config.organization, 80 | &config.common_name, 81 | &local.serial_number, 82 | ) 83 | .unwrap(); 84 | 85 | debug!( 86 | "encoded local_id {} {} {}", 87 | config.organization, config.common_name, local.serial_number 88 | ); 89 | 90 | let local_addrs = address::local(&local.address_family, &local.address); 91 | for organization in registry { 92 | let _span_organization = debug_span!("org", name = organization.organization).entered(); 93 | 94 | for node in &organization.nodes { 95 | let _span_node = debug_span!("node", cn = node.common_name).entered(); 96 | 97 | if node.common_name == config.common_name { 98 | continue; 99 | } 100 | for remote in &node.endpoints { 101 | let _span_endpoint = 102 | debug_span!("endpoint", sn = remote.serial_number).entered(); 103 | 104 | if remote.address_family != local.address_family { 105 | continue; 106 | } 107 | 108 | let remote_id = asn::encode_identity( 109 | &organization.organization, 110 | &node.common_name, 111 | &remote.serial_number, 112 | ) 113 | .unwrap(); 114 | 115 | let remote_addrs = address::remote(&remote.address_family, &remote.address); 116 | let name = 117 | generate_name(&desired, format!("{}-{}", &local_id, &remote_id).as_bytes()); 118 | desired.insert(name.clone()); 119 | let result = client 120 | .load_conn( 121 | &name, 122 | vici::Endpoint { 123 | id: local_id.clone(), 124 | addrs: local_addrs.clone(), 125 | port: local.port, 126 | pubkey: public_key.clone(), 127 | }, 128 | vici::Endpoint { 129 | id: remote_id, 130 | addrs: remote_addrs, 131 | port: remote.port, 132 | pubkey: organization.public_key.clone(), 133 | }, 134 | local.updown.clone(), 135 | local.fwmark.clone(), 136 | ) 137 | .await; 138 | 139 | if let Err(err) = result { 140 | warn!("load connection error: {}", err); 141 | continue; 142 | } 143 | 144 | info!("loaded connection"); 145 | 146 | client.initiate(&name).await?; 147 | } 148 | } 149 | } 150 | } 151 | 152 | let current = HashSet::::from_iter(client.get_conns().await?.into_iter()); 153 | 154 | for conn in current.difference(&desired) { 155 | client.unload_conn(conn).await?; 156 | client.terminate(conn).await?; 157 | } 158 | 159 | Ok(()) 160 | } 161 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | use clap::{Parser, Subcommand}; 4 | use ranet::{config::Config, reconcile, registry::Registry}; 5 | use tracing_subscriber::EnvFilter; 6 | 7 | /// ranet 8 | #[derive(Parser, Debug)] 9 | #[command(author, version, about, long_about = None)] 10 | struct Args { 11 | /// path to config file 12 | #[arg(short, long)] 13 | config: String, 14 | /// path to registry file 15 | #[arg(short, long)] 16 | registry: String, 17 | /// path to private key 18 | #[arg(short, long)] 19 | key: String, 20 | /// path to vici control socket 21 | #[arg(short, long, default_value = "/run/charon.vici")] 22 | vici: String, 23 | #[command(subcommand)] 24 | command: Commands, 25 | } 26 | 27 | #[derive(Subcommand, Debug)] 28 | enum Commands { 29 | Up, 30 | Down, 31 | } 32 | 33 | #[tokio::main] 34 | async fn main() -> Result<(), ranet::error::Error> { 35 | tracing_subscriber::fmt::fmt() 36 | .pretty() 37 | .with_env_filter(EnvFilter::from_default_env()) 38 | .init(); 39 | 40 | let args = Args::parse(); 41 | 42 | let config = tokio::fs::read(&args.config).await?; 43 | let config: Config = serde_json::from_slice(&config)?; 44 | 45 | let key = tokio::fs::read(&args.key).await?; 46 | 47 | match &args.command { 48 | Commands::Up => { 49 | let registry = tokio::fs::read(&args.registry).await?; 50 | let registry: Registry = serde_json::from_slice(®istry)?; 51 | 52 | reconcile(&args.vici, &config, ®istry, &key).await?; 53 | } 54 | Commands::Down => { 55 | reconcile(&args.vici, &config, &vec![], &key).await?; 56 | } 57 | } 58 | 59 | Ok(()) 60 | } 61 | -------------------------------------------------------------------------------- /src/registry.rs: -------------------------------------------------------------------------------- 1 | use serde::{de::IgnoredAny, Deserialize}; 2 | 3 | pub type Registry = Vec; 4 | 5 | #[derive(Debug, Deserialize, PartialEq)] 6 | #[serde(deny_unknown_fields)] 7 | pub struct Organization { 8 | pub public_key: String, 9 | pub organization: String, 10 | pub nodes: Vec, 11 | } 12 | 13 | #[derive(Debug, Deserialize, PartialEq)] 14 | #[serde(deny_unknown_fields)] 15 | pub struct Node { 16 | pub common_name: String, 17 | pub endpoints: Vec, 18 | pub remarks: Option, 19 | } 20 | 21 | #[derive(Debug, Deserialize, PartialEq)] 22 | #[serde(deny_unknown_fields)] 23 | pub struct Endpoint { 24 | pub serial_number: String, 25 | pub address_family: String, 26 | pub address: Option, 27 | pub port: u16, 28 | } 29 | 30 | #[cfg(test)] 31 | mod test { 32 | use super::*; 33 | 34 | #[test] 35 | fn deserialize() { 36 | let data = r#" 37 | [ 38 | { 39 | "public_key": "", 40 | "organization": "nickcao", 41 | "nodes": [ 42 | { 43 | "common_name": "nrt0", 44 | "endpoints": [ 45 | { 46 | "serial_number": "0", 47 | "address_family": "ip4", 48 | "port": 3000 49 | }, 50 | { 51 | "serial_number": "1", 52 | "address_family": "ip6", 53 | "address": "nrt0.nichi.link", 54 | "port": 4000 55 | } 56 | ], 57 | "remarks": { 58 | "some": "random note", 59 | "other": false 60 | } 61 | } 62 | ] 63 | } 64 | ] 65 | "#; 66 | 67 | let value: Registry = serde_json::from_str(data).unwrap(); 68 | 69 | assert_eq!( 70 | value, 71 | vec![Organization { 72 | public_key: "".to_string(), 73 | organization: "nickcao".to_string(), 74 | nodes: vec![Node { 75 | common_name: "nrt0".to_string(), 76 | endpoints: vec![ 77 | Endpoint { 78 | serial_number: "0".to_string(), 79 | address_family: "ip4".to_string(), 80 | address: None, 81 | port: 3000 82 | }, 83 | Endpoint { 84 | serial_number: "1".to_string(), 85 | address_family: "ip6".to_string(), 86 | address: Some("nrt0.nichi.link".to_string()), 87 | port: 4000 88 | } 89 | ], 90 | remarks: Some(IgnoredAny) 91 | }] 92 | }] 93 | ) 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/vici.rs: -------------------------------------------------------------------------------- 1 | use crate::error::Error; 2 | use futures::TryStreamExt; 3 | use serde::{Deserialize, Serialize}; 4 | use std::{collections::HashMap, path::Path}; 5 | use tracing::debug; 6 | 7 | pub struct Client { 8 | client: rsvici::Client, 9 | } 10 | 11 | impl Client { 12 | pub async fn connect>(path: P) -> Result { 13 | let client = rsvici::unix::connect(path).await?; 14 | Ok(Self { client }) 15 | } 16 | pub async fn version(&mut self) -> Result { 17 | let v: Version = self.client.request("version", ()).await?; 18 | let v = semver::Version::parse(&v.version)?; 19 | Ok(v) 20 | } 21 | pub async fn load_key(&mut self, key: &[u8]) -> Result<(), Error> { 22 | let key = Key { 23 | r#type: "any", 24 | data: std::str::from_utf8(key)?, 25 | }; 26 | let res: Status = self.client.request("load-key", key).await?; 27 | res.parse() 28 | } 29 | pub async fn load_conn( 30 | &mut self, 31 | name: &str, 32 | local: Endpoint, 33 | remote: Endpoint, 34 | updown: Option, 35 | fwmark: Option, 36 | ) -> Result<(), Error> { 37 | let conn = Connection::new(local, remote, updown, fwmark); 38 | let resp: Status = self 39 | .client 40 | .request("load-conn", HashMap::from([(name, conn)])) 41 | .await?; 42 | resp.parse() 43 | } 44 | pub async fn initiate(&mut self, name: &str) -> Result<(), Error> { 45 | let sas = self.list_sas(name).await?; 46 | 47 | for sa in sas.iter().flat_map(|v| v.values()) { 48 | if !sa.child_sas.is_empty() || sa.tasks_active.contains(&"CHILD_CREATE".to_string()) { 49 | return Ok(()); 50 | } 51 | } 52 | 53 | debug!("initiating sa {}", name); 54 | 55 | let _res: Status = self 56 | .client 57 | .request( 58 | "initiate", 59 | Initiate { 60 | ike: name, 61 | child: "default", 62 | timeout: -1, 63 | init_limits: false, 64 | }, 65 | ) 66 | .await?; 67 | Ok(()) 68 | } 69 | pub async fn terminate(&mut self, name: &str) -> Result<(), Error> { 70 | let _res: Status = self 71 | .client 72 | .request( 73 | "terminate", 74 | Terminate { 75 | ike: name, 76 | timeout: -1, 77 | }, 78 | ) 79 | .await?; 80 | Ok(()) 81 | } 82 | pub async fn get_conns(&mut self) -> Result, Error> { 83 | let res: Conns = self.client.request("get-conns", ()).await?; 84 | Ok(res.conns) 85 | } 86 | pub async fn unload_conn(&mut self, name: &str) -> Result<(), Error> { 87 | let res: Status = self.client.request("unload-conn", Unload { name }).await?; 88 | res.parse() 89 | } 90 | async fn list_sas(&mut self, name: &str) -> Result>, Error> { 91 | let sas = self.client.stream_request::( 92 | "list-sas", 93 | "list-sa", 94 | ListSAs { ike: name }, 95 | ); 96 | 97 | Ok(sas.try_collect::>().await?) 98 | } 99 | } 100 | 101 | #[derive(Debug, Deserialize)] 102 | struct Version { 103 | version: String, 104 | } 105 | 106 | #[derive(Debug, Serialize)] 107 | struct Key<'a, 'b> { 108 | r#type: &'a str, 109 | data: &'b str, 110 | } 111 | 112 | #[derive(Debug, Deserialize)] 113 | struct Status { 114 | success: bool, 115 | errmsg: Option, 116 | } 117 | 118 | impl Status { 119 | fn parse(self) -> Result<(), Error> { 120 | match self { 121 | Status { success: true, .. } => Ok(()), 122 | Status { 123 | success: false, 124 | errmsg, 125 | } => Err(Error::Protocol(errmsg)), 126 | } 127 | } 128 | } 129 | 130 | #[derive(Debug, Deserialize)] 131 | struct Conns { 132 | conns: Vec, 133 | } 134 | 135 | #[derive(Debug, Serialize)] 136 | struct Unload<'a> { 137 | name: &'a str, 138 | } 139 | 140 | #[derive(Debug, Serialize)] 141 | struct Initiate<'a, 'b> { 142 | ike: &'a str, 143 | child: &'b str, 144 | timeout: isize, 145 | init_limits: bool, 146 | } 147 | 148 | #[derive(Debug, Serialize)] 149 | struct ListSAs<'a> { 150 | ike: &'a str, 151 | } 152 | 153 | #[derive(Debug, Deserialize)] 154 | #[serde(rename_all = "kebab-case")] 155 | struct SA { 156 | #[serde(default)] 157 | tasks_active: Vec, 158 | child_sas: HashMap, 159 | } 160 | 161 | type SAs = HashMap; 162 | 163 | #[derive(Debug, Serialize)] 164 | struct Terminate<'a> { 165 | ike: &'a str, 166 | timeout: isize, 167 | } 168 | 169 | #[derive(Debug, Serialize)] 170 | struct Child { 171 | // esp_proposals 172 | local_ts: Vec, 173 | remote_ts: Vec, 174 | updown: String, 175 | mode: &'static str, 176 | dpd_action: &'static str, 177 | set_mark_out: String, 178 | start_action: &'static str, 179 | close_action: &'static str, 180 | } 181 | 182 | #[derive(Debug, Serialize)] 183 | struct Authentication { 184 | auth: &'static str, 185 | pubkeys: Vec, 186 | id: String, 187 | } 188 | 189 | #[derive(Debug, Serialize)] 190 | struct Connection { 191 | version: u32, 192 | local_addrs: Vec, 193 | remote_addrs: Vec, 194 | local_port: u16, 195 | remote_port: u16, 196 | // proposals 197 | // dscp 198 | encap: bool, 199 | mobike: bool, 200 | dpd_delay: u64, 201 | keyingtries: u32, 202 | unique: &'static str, 203 | if_id_in: &'static str, 204 | if_id_out: &'static str, 205 | local: Authentication, 206 | remote: Authentication, 207 | children: HashMap<&'static str, Child>, 208 | } 209 | 210 | pub struct Endpoint { 211 | pub id: String, 212 | pub addrs: Vec, 213 | pub port: u16, 214 | pub pubkey: String, 215 | } 216 | 217 | impl Connection { 218 | fn new( 219 | local: Endpoint, 220 | remote: Endpoint, 221 | updown: Option, 222 | fwmark: Option, 223 | ) -> Self { 224 | Self { 225 | version: 2, 226 | local_addrs: local.addrs, 227 | remote_addrs: remote.addrs, 228 | local_port: local.port, 229 | remote_port: remote.port, 230 | encap: true, 231 | mobike: false, 232 | dpd_delay: 10, 233 | keyingtries: 0, 234 | unique: "replace", 235 | if_id_in: "%unique", 236 | if_id_out: "%unique", 237 | local: Authentication { 238 | auth: "pubkey", 239 | pubkeys: vec![local.pubkey], 240 | id: local.id, 241 | }, 242 | remote: Authentication { 243 | auth: "pubkey", 244 | pubkeys: vec![remote.pubkey], 245 | id: remote.id, 246 | }, 247 | children: HashMap::from([( 248 | "default", 249 | Child { 250 | local_ts: vec!["0.0.0.0/0".to_string(), "::/0".to_string()], 251 | remote_ts: vec!["0.0.0.0/0".to_string(), "::/0".to_string()], 252 | updown: updown.unwrap_or_default(), 253 | mode: "tunnel", 254 | dpd_action: "restart", 255 | set_mark_out: fwmark.unwrap_or_default(), 256 | start_action: "none", 257 | close_action: "none", 258 | }, 259 | )]), 260 | } 261 | } 262 | } 263 | --------------------------------------------------------------------------------