diff --git a/.idea/trifid.iml b/.idea/trifid.iml index b4614b5..bd7461a 100644 --- a/.idea/trifid.iml +++ b/.idea/trifid.iml @@ -9,6 +9,7 @@ + diff --git a/Cargo.lock b/Cargo.lock index 13d30af..7608e40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,7 +14,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "bytes", "futures-core", "futures-sink", @@ -52,7 +52,7 @@ dependencies = [ "actix-utils", "ahash 0.8.3", "base64 0.21.0", - "bitflags", + "bitflags 1.3.2", "brotli", "bytes", "bytestring", @@ -609,12 +609,41 @@ dependencies = [ "num-traits", ] +[[package]] +name = "bindgen" +version = "0.66.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +dependencies = [ + "bitflags 2.3.2", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.16", + "which", +] + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded" + [[package]] name = "bitvec" version = "1.0.1" @@ -775,6 +804,15 @@ dependencies = [ "jobserver", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -813,13 +851,24 @@ dependencies = [ "inout", ] +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ - "bitflags", + "bitflags 1.3.2", "clap_derive 3.2.25", "clap_lex 0.2.4", "indexmap", @@ -846,7 +895,7 @@ checksum = "914c8c79fb560f238ef6429439a30023c862f7a28e688c58f7203f12b29970bd" dependencies = [ "anstream", "anstyle", - "bitflags", + "bitflags 1.3.2", "clap_lex 0.4.1", "strsim", ] @@ -1005,7 +1054,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crossterm_winapi", "libc", "mio", @@ -1511,6 +1560,12 @@ dependencies = [ "polyval", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "gloo-timers" version = "0.2.6" @@ -1523,6 +1578,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gobuild" +version = "0.1.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e156a4ddbf3deb5e8116946c111413bd9a5679bdc1536c78a60618a7a9ac9e" +dependencies = [ + "cc", +] + [[package]] name = "h2" version = "0.3.19" @@ -1860,12 +1924,28 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + [[package]] name = "libm" version = "0.1.4" @@ -1991,13 +2071,21 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nebula-ffi" +version = "0.1.0" +dependencies = [ + "bindgen", + "gobuild", +] + [[package]] name = "nix" version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", "static_assertions", @@ -2080,7 +2168,7 @@ version = "0.10.52" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01b8574602df80f7b85fdfc5392fa884a4e3b3f4f35402c070ab34c3d3f78d56" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "foreign-types", "libc", @@ -2233,6 +2321,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "pem" version = "1.1.1" @@ -2289,7 +2383,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ "autocfg", - "bitflags", + "bitflags 1.3.2", "cfg-if", "concurrent-queue", "libc", @@ -2316,6 +2410,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "prettyplease" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9825a04601d60621feed79c4e6b56d65db77cdca55cef43b46b0de1096d1c282" +dependencies = [ + "proc-macro2", + "syn 2.0.16", +] + [[package]] name = "proc-macro-crate" version = "0.1.5" @@ -2457,7 +2561,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -2466,7 +2570,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -2619,6 +2723,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -2634,7 +2744,7 @@ version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", @@ -2875,7 +2985,7 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2855b3715770894e67cbfa3df957790aa0c9edc3bf06efa1a84d77fa0839d1" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -3022,6 +3132,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + [[package]] name = "signal-hook" version = "0.3.15" @@ -3149,7 +3265,7 @@ dependencies = [ "atoi", "base64 0.13.1", "bigdecimal", - "bitflags", + "bitflags 1.3.2", "byteorder", "bytes", "chrono", @@ -3330,7 +3446,7 @@ dependencies = [ [[package]] name = "tfclient" -version = "0.1.8" +version = "0.2.0" dependencies = [ "base64 0.21.0", "base64-serde", @@ -3343,6 +3459,7 @@ dependencies = [ "hex", "ipnet", "log", + "nebula-ffi", "openssl-sys", "reqwest", "serde", @@ -3956,6 +4073,17 @@ dependencies = [ "webpki", ] +[[package]] +name = "which" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +dependencies = [ + "either", + "libc", + "once_cell", +] + [[package]] name = "whoami" version = "1.4.0" diff --git a/Cargo.toml b/Cargo.toml index 17eb7c0..7b837dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,5 +6,6 @@ members = [ "tfclient", "trifid-pki", "dnapi-rs", - "tfcli" + "tfcli", + "nebula-ffi" ] \ No newline at end of file diff --git a/nebula-ffi/Cargo.toml b/nebula-ffi/Cargo.toml new file mode 100644 index 0000000..e1b6fb7 --- /dev/null +++ b/nebula-ffi/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "nebula-ffi" +version = "0.1.0" +edition = "2021" +description = "A Rust wrapper crate for communicating with Nebula via a CGO FFI." +license = "GPL-3.0-or-later" +documentation = "https://docs.rs/nebula-ffi" +homepage = "https://man.e3t.cc/~core/trifid-docs" +repository = "https://git.e3t.cc/~core/trifid" + +[dependencies] + +[build-dependencies] +gobuild = "0.1.0-alpha.2" +bindgen = "0.66.1" \ No newline at end of file diff --git a/nebula-ffi/README.md b/nebula-ffi/README.md new file mode 100644 index 0000000..d830bd4 --- /dev/null +++ b/nebula-ffi/README.md @@ -0,0 +1,3 @@ +# Nebula-FFI + +A CGO FFI interface for [Nebula](https://github.com/slackhq/nebula) and a Rust crate for communicating with it. \ No newline at end of file diff --git a/nebula-ffi/build.rs b/nebula-ffi/build.rs new file mode 100644 index 0000000..fce0147 --- /dev/null +++ b/nebula-ffi/build.rs @@ -0,0 +1,26 @@ +use std::env; +use std::path::PathBuf; +use bindgen::CargoCallbacks; + +fn main() { + gobuild::Build::new().file("main.go").compile("nebulaffi"); + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + + println!("cargo:rustc-link-search={}", out_path.display()); + println!("cargo:rustc-link-lib=static=nebulaffi"); + println!("cargo:rerun-if-changed=go.mod"); + println!("cargo:rerun-if-changed=go.sum"); + println!("cargo:rerun-if-changed=main.go"); + + let bindings = bindgen::Builder::default() + .header(out_path.join("libnebulaffi.h").display().to_string()) + .parse_callbacks(Box::new(CargoCallbacks)) + .generate() + .expect("Error generating CFFI bindings"); + + + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} \ No newline at end of file diff --git a/nebula-ffi/go.mod b/nebula-ffi/go.mod new file mode 100644 index 0000000..f279883 --- /dev/null +++ b/nebula-ffi/go.mod @@ -0,0 +1,39 @@ +module main + +go 1.20 + +require ( + github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432 // indirect + github.com/flynn/noise v1.0.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/gopacket v1.1.19 // indirect + github.com/imdario/mergo v0.3.15 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/miekg/dns v1.1.54 // indirect + github.com/nbrownus/go-metrics-prometheus v0.0.0-20210712211119-974a6260965f // indirect + github.com/prometheus/client_golang v1.15.1 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect + github.com/slackhq/nebula v1.7.2 // indirect + github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 // indirect + github.com/vishvananda/netlink v1.1.0 // indirect + github.com/vishvananda/netns v0.0.4 // indirect + golang.org/x/crypto v0.8.0 // indirect + golang.org/x/mod v0.10.0 // indirect + golang.org/x/net v0.9.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/term v0.8.0 // indirect + golang.org/x/tools v0.8.0 // indirect + golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect + golang.zx2c4.com/wireguard/windows v0.5.3 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) diff --git a/nebula-ffi/go.sum b/nebula-ffi/go.sum new file mode 100644 index 0000000..f41152f --- /dev/null +++ b/nebula-ffi/go.sum @@ -0,0 +1,231 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432 h1:M5QgkYacWj0Xs8MhpIK/5uwU02icXpEoSo9sM2aRCps= +github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432/go.mod h1:xwIwAxMvYnVrGJPe2FKx5prTrnAjGOD8zvDOnxnrrkM= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= +github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= +github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= +github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= +github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nbrownus/go-metrics-prometheus v0.0.0-20210712211119-974a6260965f h1:8dM0ilqKL0Uzl42GABzzC4Oqlc3kGRILz0vgoff7nwg= +github.com/nbrownus/go-metrics-prometheus v0.0.0-20210712211119-974a6260965f/go.mod h1:nwPd6pDNId/Xi16qtKrFHrauSwMNuvk+zcjk89wrnlA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= +github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/slackhq/nebula v1.7.2 h1:Rko1Mlksz/nC0c919xjGpB8uOSrTJ5e6KPgZx+lVfYw= +github.com/slackhq/nebula v1.7.2/go.mod h1:cnaoahkUipDs1vrNoIszyp0QPRIQN9Pm68ppQEW1Fhg= +github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8= +github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= +github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= +golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= +golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= +golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/nebula-ffi/main.go b/nebula-ffi/main.go new file mode 100644 index 0000000..b086bf8 --- /dev/null +++ b/nebula-ffi/main.go @@ -0,0 +1,106 @@ +package main + +import "C" +import ( + "os" + "fmt" + "github.com/sirupsen/logrus" + "github.com/slackhq/nebula" + "github.com/slackhq/nebula/config" +) + +// A version string that can be set with +// +// -ldflags "-X main.Build=SOMEVERSION" +// +// at compile-time. +var Build string + +var neb_config *config.C +var control *nebula.Control + +//export NebulaSetup +func NebulaSetup(configPathCStr *C.char, configTest bool) (reterr *C.char) { + configPath := C.GoString(configPathCStr) + + if configPath == "" { + fmt.Println("a config path must be provided") + return C.CString("a config path must be provided") + } + + fmt.Println(configPath) + + fmt.Println("Loading configuration from", configPath) + + l := logrus.New() + l.Out = os.Stdout + + neb_config = config.NewC(l) + err := neb_config.Load(configPath) + if err != nil { + fmt.Println(err.Error()) + return C.CString(err.Error()) + } + + ctrl, err := nebula.Main(neb_config, configTest, Build, l, nil) + control = ctrl + + if err != nil { + fmt.Println(err.Error()) + return C.CString(err.Error()) + } + fmt.Println("NO_FAILURE") + return C.CString("NO_FAILURE") +} + +//export NebulaReloadConfig +func NebulaReloadConfig() (reterr *C.char) { + if neb_config == nil { + fmt.Println("NebulaSetup has not yet been called") + return C.CString("NebulaSetup has not yet been called") + } + neb_config.ReloadConfig() + return C.CString("NO_FAILURE") +} + +//export NebulaStart +func NebulaStart() (reterr *C.char) { + if control == nil { + fmt.Println("NebulaSetup has not yet been called") + return C.CString("NebulaSetup has not yet been called") + } + control.Start() + return C.CString("NO_FAILURE") +} + +//export NebulaStop +func NebulaStop() (reterr *C.char) { + if control == nil { + fmt.Println("NebulaSetup has not yet been called") + return C.CString("NebulaSetup has not yet been called") + } + control.Stop() + return C.CString("NO_FAILURE") +} + +//export NebulaShutdownBlock +func NebulaShutdownBlock() (reterr *C.char) { + if control == nil { + fmt.Println("NebulaSetup has not yet been called") + return C.CString("NebulaSetup has not yet been called") + } + control.ShutdownBlock() + return C.CString("NO_FAILURE") +} + +//export NebulaRebindUDP +func NebulaRebindUDP() (reterr *C.char) { + if control == nil { + fmt.Println("NebulaSetup has not yet been called") + return C.CString("NebulaSetup has not yet been called") + } + control.RebindUDPServer() + return C.CString("NO_FAILURE") +} + +func main() {} \ No newline at end of file diff --git a/nebula-ffi/src/lib.rs b/nebula-ffi/src/lib.rs new file mode 100644 index 0000000..6cf7f36 --- /dev/null +++ b/nebula-ffi/src/lib.rs @@ -0,0 +1,217 @@ +//! # nebula-ffi + +#![warn(clippy::pedantic)] +#![warn(clippy::nursery)] +#![deny(clippy::unwrap_used)] +#![deny(clippy::expect_used)] +#![deny(missing_docs)] +#![deny(clippy::missing_errors_doc)] +#![deny(clippy::missing_panics_doc)] +#![deny(clippy::missing_safety_doc)] + + +#[allow(non_upper_case_globals)] +#[allow(non_camel_case_types)] +#[allow(non_snake_case)] +#[allow(missing_docs)] +#[allow(unused)] +#[allow(clippy::derive_partial_eq_without_eq)] +pub mod generated { + include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +} + +use std::error::Error; +use std::ffi::{c_char, CString}; +use std::fmt::{Display, Formatter}; +use std::path::{Path}; +use generated::GoString; + + +impl From<&str> for GoString { + #[allow(clippy::cast_possible_wrap)] + #[allow(clippy::expect_used)] + fn from(value: &str) -> Self { + let c_str = CString::new(value).expect("CString::new() failed"); + let ptr = c_str.as_ptr(); + let go_string = GoString { + p: ptr, + n: c_str.as_bytes().len() as isize + }; + go_string + } +} + +#[allow(clippy::expect_used)] +fn cstring_to_string(cstr_ptr: *mut c_char) -> String { + let cstr = unsafe { CString::from_raw(cstr_ptr) }; + cstr.to_string_lossy().to_string() +} + +/// An instance of a Nebula Control and Config object. This struct does not actually store any information - it is stored in globals in the Go wrapper, however this struct is used to provide typesafety. +pub struct NebulaInstance {} + +impl NebulaInstance { + /// Creates a new `NebulaInstance` by calling `NebulaSetup` with the given config path and configTest parameters. + /// # Errors + /// This function will return errors in many, many circumstances. It is not fully documented the scope of errors that may occur. + /// # Panics + /// This function will panic if memory is corrupted while communicating with Go. + pub fn new(config_path: &Path, config_test: bool) -> Result> { + let mut config_path_bytes = unsafe { config_path.display().to_string().as_bytes_mut().to_vec() }; + config_path_bytes.push(0u8); + let config_test_u8 = u8::from(config_test); + + let res; + + unsafe { + res = generated::NebulaSetup(config_path_bytes.as_mut_ptr().cast::(), config_test_u8); + } + + let res = cstring_to_string(res); + + if res == "NO_FAILURE" { + Ok(Self {}) + } else { + Err(NebulaError::from_string(&res).into()) + } + } + + /// Reloads the Nebula configuration file. Not all configuration values can be reloaded, some may require a full stop and re-setup of Nebula to be applied. + /// # Errors + /// This function will return an error if an error is returned by the CGOFFI layer. + pub fn reload_config(&self) -> Result<(), Box> { + let res; + + unsafe { + res = generated::NebulaReloadConfig(); + } + + let res = cstring_to_string(res); + + if res == "NO_FAILURE" { + Ok(()) + } else { + Err(NebulaError::from_string(&res).into()) + } + } + + /// Starts the Nebula packet listener server if it is not already running. + /// # Errors + /// This function will return an error if an error is returned by the CGOFFI layer. + pub fn start(&self) -> Result<(), Box> { + let res; + + unsafe { + res = generated::NebulaStart(); + } + + let res = cstring_to_string(res); + + if res == "NO_FAILURE" { + Ok(()) + } else { + Err(NebulaError::from_string(&res).into()) + } + } + + /// Signals nebula to shutdown, returns after the shutdown is complete + /// # Errors + /// This function will return an error if an error is returned by the CGOFFI layer. + pub fn stop(&self) -> Result<(), Box> { + let res; + + unsafe { + res = generated::NebulaStop(); + } + + let res = cstring_to_string(res); + + if res == "NO_FAILURE" { + Ok(()) + } else { + Err(NebulaError::from_string(&res).into()) + } + } + + /// This function blocks until a SIGTERM or SIGINT is received, then stops the Nebula packet listener server if it is not already stopped. + /// # Errors + /// This function will return an error if an error is returned by the CGOFFI layer. + pub fn block_and_stop(&self) -> Result<(), Box> { + let res; + + unsafe { + res = generated::NebulaShutdownBlock(); + } + + let res = cstring_to_string(res); + + if res == "NO_FAILURE" { + Ok(()) + } else { + Err(NebulaError::from_string(&res).into()) + } + } + + /// Asks the UDP listener to rebind it's listener. Mainly used on mobile clients when interfaces change + /// # Errors + /// This function will return an error if an error is returned by the CGOFFI layer. + pub fn rebind_udp(&self) -> Result<(), Box> { + let res; + + unsafe { + res = generated::NebulaRebindUDP(); + } + + let res = cstring_to_string(res); + + if res == "NO_FAILURE" { + Ok(()) + } else { + Err(NebulaError::from_string(&res).into()) + } + } +} + +#[derive(Debug)] +/// An enumeration of all known errors that can be returned by Nebula. As errors are passed by string, this can be a little bit janky, but it works most of the time. +pub enum NebulaError { + /// Returned by nebula when the TUN/TAP device already exists + DeviceOrResourceBusy { + /// The complete error string returned by the Nebula wrapper + error_str: String + }, + /// An unknown error that the error parser couldn't figure out how to parse. + Unknown { + /// The complete error string returned by the Nebula wrapper + error_str: String + }, + /// Occurs if you call a function before NebulaSetup has been called + NebulaNotSetup { + /// The complete error string returned by the Nebula wrapper + error_str: String + } +} +impl Display for NebulaError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::DeviceOrResourceBusy { error_str } => write!(f, "device or resource busy ({error_str})"), + Self::Unknown { error_str } => write!(f, "unknown error ({error_str})"), + Self::NebulaNotSetup { error_str } => write!(f, "attempted to call a function depending on global variable before NebulaSetup ({error_str})") + } + } +} +impl Error for NebulaError {} + +impl NebulaError { + /// Converts a string error from the Nebula CGO wrapper into a Rust strongtyped error. + #[must_use] + pub fn from_string(string: &str) -> Self { + if string.starts_with("device or resource busy") { + Self::DeviceOrResourceBusy { error_str: string.to_string() } + } else if string.starts_with("NebulaSetup has not yet been called") { + Self::NebulaNotSetup { error_str: string.to_string() } + } else { + Self::Unknown { error_str: string.to_string() } + } + } +} \ No newline at end of file diff --git a/tfclient/Cargo.toml b/tfclient/Cargo.toml index 6cbb715..30749f8 100644 --- a/tfclient/Cargo.toml +++ b/tfclient/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tfclient" -version = "0.1.8" +version = "0.2.0" edition = "2021" description = "An open-source reimplementation of a Defined Networking-compatible client" license = "GPL-3.0-or-later" @@ -31,6 +31,7 @@ base64-serde = "0.7.0" dnapi-rs = { version = "0.1", path = "../dnapi-rs" } serde_yaml = "0.9.19" openssl-sys = { version = "0.9.83", features = ["vendored"] } +nebula-ffi = { version = "0.1", path = "../nebula-ffi" } [build-dependencies] serde = { version = "1.0.157", features = ["derive"] } diff --git a/tfclient/build.rs b/tfclient/build.rs deleted file mode 100644 index b10ea90..0000000 --- a/tfclient/build.rs +++ /dev/null @@ -1,222 +0,0 @@ -use flate2::read::GzDecoder; -use reqwest::blocking::Response; -use reqwest::header::HeaderMap; -use std::fs; -use std::fs::{remove_file, File}; -use std::io::{Read, Write}; -use std::os::unix::fs::PermissionsExt; -use std::path::Path; -use std::process::{Command, Output}; -use tar::Archive; - -#[derive(serde::Deserialize, Debug)] -struct GithubRelease { - name: String, - assets: Vec, -} - -#[derive(serde::Deserialize, Debug)] -struct GithubUser {} - -#[derive(serde::Deserialize, Debug)] -struct GithubReleaseAsset { - browser_download_url: String, - name: String, - size: i64, -} - -fn main() { - if Path::new(&format!( - "{}/{}", - std::env::var("OUT_DIR").unwrap(), - "noredownload" - )) - .exists() - && std::env::var("TFBUILD_FORCE_REDOWNLOAD").is_err() - { - println!("noredownload exists and TFBUILD_FORCE_REDOWNLOAD is not set. Not redoing build process."); - return; - } - - println!("[*] Fetching nebula releaseinfo..."); - - let mut headers = HeaderMap::new(); - let mut has_api_key = false; - - if let Ok(api_key) = std::env::var("GH_API_KEY") { - headers.insert( - "Authorization", - format!("Bearer {}", api_key).parse().unwrap(), - ); - has_api_key = true; - } - - let client = reqwest::blocking::Client::builder() - .user_agent("curl/7.57.1") - .default_headers(headers) - .build() - .unwrap(); - - let resp: Response = client - .get("https://api.github.com/repos/slackhq/nebula/releases/latest") - .send() - .unwrap(); - - if resp - .headers() - .get("X-Ratelimit-Remaining") - .unwrap() - .to_str() - .unwrap() - == "0" - { - println!("You've been ratelimited from the GitHub API. Wait a while (1 hour)"); - if !has_api_key { - println!("You can also set a GitHub API key with the environment variable GH_API_KEY, which will increase your ratelimit ( a lot )"); - } - panic!("Ratelimited"); - } - - let release: GithubRelease = resp.json().unwrap(); - - println!("[*] Fetching target triplet..."); - let target = std::env::var("TARGET").unwrap(); - - println!("[*] Compiling for target {}", target); - - let target_file = match target.as_str() { - "x86_64-apple-darwin" | "aarch64-apple-darwin" => "nebula-darwin", - "x86_64-unknown-freebsd" => "nebula-freebsd-amd64", - "x86_64-unknown-linux-gnu" | "x86_64-unknown-linux-musl" => "nebula-linux-amd64", - "armv5te-unknown-linux-gnueabi" => "nebula-linux-arm-5", - "arm-unknown-linux-gnueabi" | "arm-unknown-linux-gnueabihf" => "nebula-linux-arm-6", - "armv7-unknown-linux-gnueabihf" | "armv7-unknown-linux-gnueabi" => "nebula-linux-arm-7", - "aarch64-unknown-linux-gnu" | "aarch64-unknown-linux-musl" => "nebula-linux-arm64", - "x86_64-pc-windows-msvc" => "nebula-windows-amd64", - "aarch64-pc-windows-msvc" => "nebula-windows-arm64", - _ => { - println!("This architecture is not supported yet :("); - println!("Nebula has a limited set of architectures it is able to function on."); - println!("tfclient can only be compiled on these architectures."); - println!("See https://github.com/slackhq/nebula/releases for a list of supported architectures"); - println!("Is your system supported by Nebula? Shoot a message to the mailing list. Include the target triplet (above) in your response, as well as a link to the functioning Nebula binary. We will happily add your machine to the list!"); - panic!("Unsupported architecture"); - } - }; - - println!("[*] Embedding {} {}", target_file, release.name); - - let download = release - .assets - .iter() - .find(|r| r.name == format!("{}.tar.gz", target_file)) - .expect("That architecture isn't avaliable :("); - - println!( - "[*] Downloading {}.tar.gz ({}, {} bytes) from {}", - target_file, target, download.size, download.browser_download_url - ); - - let response = reqwest::blocking::get(&download.browser_download_url).unwrap(); - let content = response.bytes().unwrap().to_vec(); - let bytes = content.as_slice(); - - let tar = GzDecoder::new(bytes); - let mut archive = Archive::new(tar); - let entries = archive.entries().unwrap(); - - let mut nebula_bin = vec![]; - let mut nebula_cert_bin = vec![]; - let mut shasum = vec![]; - - for entry in entries { - let mut entry = entry.unwrap(); - if entry.path().unwrap() == Path::new("nebula") - || entry.path().unwrap() == Path::new("nebula.exe") - { - nebula_bin.reserve(entry.size() as usize); - entry.read_to_end(&mut nebula_bin).unwrap(); - } else if entry.path().unwrap() == Path::new("nebula-cert") - || entry.path().unwrap() == Path::new("nebula-cert.exe") - { - nebula_cert_bin.reserve(entry.size() as usize); - entry.read_to_end(&mut nebula_cert_bin).unwrap(); - } else if entry.path().unwrap() == Path::new("SHASUM256.txt") { - shasum.reserve(entry.size() as usize); - entry.read_to_end(&mut shasum).unwrap(); - } - } - - if nebula_bin.is_empty() { - panic!("[x] Release did not contain nebula binary"); - } - if nebula_cert_bin.is_empty() { - panic!("[x] Release did not contain nebula_cert binary"); - } - - let mut nebula_file = - File::create(format!("{}/nebula.bin", std::env::var("OUT_DIR").unwrap())).unwrap(); - nebula_file.write_all(&nebula_bin).unwrap(); - - codegen_version(&nebula_bin, "nebula.bin", "NEBULA"); - - let mut nebula_cert_file = File::create(format!( - "{}/nebula_cert.bin", - std::env::var("OUT_DIR").unwrap() - )) - .unwrap(); - nebula_cert_file.write_all(&nebula_cert_bin).unwrap(); - - codegen_version(&nebula_cert_bin, "nebula_cert.bin", "NEBULA_CERT"); - - // Indicate to cargo and ourselves that we have already downloaded and codegenned - File::create(format!( - "{}/{}", - std::env::var("OUT_DIR").unwrap(), - "noredownload" - )) - .unwrap(); - println!("cargo:rerun-if-changed=build.rs"); -} - -fn codegen_version(bin: &[u8], fp: &str, name: &str) { - // get version - let output = execim(bin, &vec!["-version"]); - let stdout = output.stdout; - let stdout_str = String::from_utf8(stdout).unwrap(); - if !stdout_str.starts_with("Version: ") { - panic!("Binary did not have expected version output. Unable to get version info."); - } - let mut version = stdout_str.split(' ').collect::>()[1].to_string(); - version.pop(); - - let code = format!("// This code was automatically @generated by build.rs. It should not be modified.\npub const {}_BIN: &[u8] = include_bytes!(concat!(env!(\"OUT_DIR\"), \"/{}\"));\npub const {}_VERSION: &str = \"{}\";", name, fp, name, version); - - let mut file = - File::create(format!("{}/{}.rs", std::env::var("OUT_DIR").unwrap(), fp)).unwrap(); - file.write_all(code.as_bytes()).unwrap(); -} - -#[cfg(not(unix))] -fn execim(buf: &[u8], args: &Vec<&str>) -> Output { - let mut file = File::create("tmpexec.bin").unwrap(); - file.write_all(buf).unwrap(); - std::mem::drop(file); - let output = Command::new("./tmpexec.bin").args(args).output().unwrap(); - remove_file("./tmpexec.bin").unwrap(); - output -} - -#[cfg(unix)] -fn execim(buf: &[u8], args: &Vec<&str>) -> Output { - let mut file = File::create("tmpexec.bin").unwrap(); - file.write_all(buf).unwrap(); - let metadata = file.metadata().unwrap(); - let mut permissions = metadata.permissions(); - permissions.set_mode(0o0755); - fs::set_permissions("./tmpexec.bin", permissions).unwrap(); - std::mem::drop(file); - let output = Command::new("./tmpexec.bin").args(args).output().unwrap(); - remove_file("./tmpexec.bin").unwrap(); - output -} diff --git a/tfclient/src/apiworker.rs b/tfclient/src/apiworker.rs index 08290f1..84c1ce3 100644 --- a/tfclient/src/apiworker.rs +++ b/tfclient/src/apiworker.rs @@ -7,7 +7,7 @@ use url::Url; use crate::config::{load_cdata, save_cdata, TFClientConfig}; use crate::daemon::ThreadMessageSender; -use crate::dirs::get_nebulaconfig_file; +use crate::dirs::nebula_yml; use crate::nebulaworker::NebulaWorkerMessage; pub enum APIWorkerMessage { @@ -113,8 +113,7 @@ pub fn apiworker_main( cdata.dh_privkey = Some(dh_privkey); match fs::write( - get_nebulaconfig_file(&instance) - .expect("Unable to determine nebula config file location"), + nebula_yml(&instance), config, ) { Ok(_) => (), @@ -177,8 +176,7 @@ pub fn apiworker_main( }; match fs::write( - get_nebulaconfig_file(&instance) - .expect("Unable to determine nebula config file location"), + nebula_yml(&instance), config, ) { Ok(_) => (), diff --git a/tfclient/src/config.rs b/tfclient/src/config.rs index 4f69c75..5f23936 100644 --- a/tfclient/src/config.rs +++ b/tfclient/src/config.rs @@ -8,8 +8,7 @@ use dnapi_rs::client_blocking::EnrollMeta; use dnapi_rs::credentials::Credentials; use log::{debug, info}; use serde::{Deserialize, Serialize}; - -use crate::dirs::{get_cdata_dir, get_cdata_file, get_config_dir, get_config_file}; +use crate::dirs::{config_dir, tfclient_toml, tfdata_toml}; pub const DEFAULT_PORT: u16 = 8157; fn default_port() -> u16 { @@ -33,7 +32,7 @@ pub struct TFClientData { pub fn create_config(instance: &str) -> Result<(), Box> { info!("Creating config directory..."); - fs::create_dir_all(get_config_dir(instance).ok_or("Unable to load config dir")?)?; + fs::create_dir_all(config_dir(instance))?; info!("Copying default config file to config directory..."); let config = TFClientConfig { listen_port: DEFAULT_PORT, @@ -41,7 +40,7 @@ pub fn create_config(instance: &str) -> Result<(), Box> { }; let config_str = toml::to_string(&config)?; fs::write( - get_config_file(instance).ok_or("Unable to load config dir")?, + tfclient_toml(instance), config_str, )?; Ok(()) @@ -49,7 +48,7 @@ pub fn create_config(instance: &str) -> Result<(), Box> { pub fn load_config(instance: &str) -> Result> { info!("Loading config..."); - let config_file = get_config_file(instance).ok_or("Unable to load config dir")?; + let config_file = tfclient_toml(instance); if !config_file.exists() { create_config(instance)?; @@ -65,7 +64,7 @@ pub fn load_config(instance: &str) -> Result> { pub fn create_cdata(instance: &str) -> Result<(), Box> { info!("Creating data directory..."); - fs::create_dir_all(get_cdata_dir(instance).ok_or("Unable to load data dir")?)?; + fs::create_dir_all(config_dir(instance))?; info!("Copying default data file to config directory..."); let config = TFClientData { dh_privkey: None, @@ -74,7 +73,7 @@ pub fn create_cdata(instance: &str) -> Result<(), Box> { }; let config_str = toml::to_string(&config)?; fs::write( - get_cdata_file(instance).ok_or("Unable to load data dir")?, + tfdata_toml(instance), config_str, )?; Ok(()) @@ -82,7 +81,7 @@ pub fn create_cdata(instance: &str) -> Result<(), Box> { pub fn load_cdata(instance: &str) -> Result> { info!("Loading cdata..."); - let config_file = get_cdata_file(instance).ok_or("Unable to load cdata dir")?; + let config_file = tfdata_toml(instance); if !config_file.exists() { create_cdata(instance)?; @@ -98,7 +97,7 @@ pub fn load_cdata(instance: &str) -> Result> { pub fn save_cdata(instance: &str, data: TFClientData) -> Result<(), Box> { info!("Saving cdata..."); - let config_file = get_cdata_file(instance).ok_or("Unable to load cdata dir")?; + let config_file = tfdata_toml(instance); if !config_file.exists() { create_cdata(instance)?; diff --git a/tfclient/src/daemon.rs b/tfclient/src/daemon.rs index eed639c..d866d52 100644 --- a/tfclient/src/daemon.rs +++ b/tfclient/src/daemon.rs @@ -9,7 +9,7 @@ use crate::config::load_config; use crate::nebulaworker::{NebulaWorkerMessage, nebulaworker_main}; use crate::socketworker::{socketworker_main, SocketWorkerMessage}; use crate::timerworker::{timer_main, TimerWorkerMessage}; -use crate::util::check_server_url; +use crate::util::{check_server_url, shutdown}; pub fn daemon_main(name: String, server: String) { // Validate the `server` @@ -44,51 +44,7 @@ pub fn daemon_main(name: String, server: String) { match ctrlc::set_handler(move || { info!("Ctrl-C detected. Stopping threads..."); - match mainthread_transmitter - .nebula_thread - .send(NebulaWorkerMessage::Shutdown) - { - Ok(_) => (), - Err(e) => { - error!( - "Error sending shutdown message to nebula worker thread: {}", - e - ); - } - } - match mainthread_transmitter - .api_thread - .send(APIWorkerMessage::Shutdown) - { - Ok(_) => (), - Err(e) => { - error!("Error sending shutdown message to api worker thread: {}", e); - } - } - match mainthread_transmitter - .socket_thread - .send(SocketWorkerMessage::Shutdown) - { - Ok(_) => (), - Err(e) => { - error!( - "Error sending shutdown message to socket worker thread: {}", - e - ); - } - } - match mainthread_transmitter - .timer_thread - .send(TimerWorkerMessage::Shutdown) - { - Ok(_) => (), - Err(e) => { - error!( - "Error sending shutdown message to timer worker thread: {}", - e - ); - } - } + shutdown(&mainthread_transmitter); }) { Ok(_) => (), Err(e) => { @@ -124,23 +80,21 @@ pub fn daemon_main(name: String, server: String) { }); info!("Starting timer thread..."); - if !config.disable_automatic_config_updates { - let timer_transmitter = transmitter; - let timer_thread = thread::spawn(move || { - timer_main(timer_transmitter, rx_timer); - }); - info!("Waiting for timer thread to exit..."); - match timer_thread.join() { - Ok(_) => (), - Err(_) => { - error!("Error waiting for timer thread to exit."); - std::process::exit(1); - } + + let timer_transmitter = transmitter; + let timer_thread = thread::spawn(move || { + timer_main(timer_transmitter, rx_timer, config.disable_automatic_config_updates); + }); + info!("Waiting for timer thread to exit..."); + match timer_thread.join() { + Ok(_) => (), + Err(_) => { + error!("Error waiting for timer thread to exit."); + std::process::exit(1); } - info!("Timer thread exited"); - } else { - info!("automatic config updates have been disabled - not starting timer thread"); } + info!("Timer thread exited"); + info!("Waiting for socket thread to exit..."); match socket_thread.join() { diff --git a/tfclient/src/dirs.rs b/tfclient/src/dirs.rs index 07e206d..c9e2317 100644 --- a/tfclient/src/dirs.rs +++ b/tfclient/src/dirs.rs @@ -1,25 +1,44 @@ use std::path::PathBuf; -pub fn get_data_dir() -> Option { - dirs::data_dir().map(|f| f.join("tfclient/")) +#[cfg(target_os = "linux")] +pub fn config_base() -> PathBuf { + PathBuf::from("/etc/tfclient") +} +#[cfg(target_os = "windows")] +pub fn config_base() -> PathBuf { + PathBuf::from("C:\\Program Data\\e3team\\tfclient") +} +#[cfg(target_os = "macos")] +pub fn config_base() -> PathBuf { + PathBuf::from("/Library/Application Support/e3team/tfclient") +} +#[cfg(target_os = "ios")] +compile_error!("tfclient cannot be compiled for iOS"); +#[cfg(target_os = "android")] +compile_error!("tfclient cannot be compiled for Android"); +#[cfg(target_os = "freebsd")] +pub fn config_base() -> PathBuf { + PathBuf::from("/etc/tfclient") +} +#[cfg(target_os = "dragonfly")] +compile_error!("tfclient cannot be compiled for dragonfly"); +#[cfg(target_os = "openbsd")] +compile_error!("tfclient cannot be compiled for openbsd"); +#[cfg(target_os = "netbsd")] +compile_error!("tfclient cannot be compiled for netbsd"); + +pub fn config_dir(instance: &str) -> PathBuf { + config_base().join(format!("{}/", instance)) } -pub fn get_config_dir(instance: &str) -> Option { - dirs::config_dir().map(|f| f.join("tfclient/").join(format!("{}/", instance))) +pub fn tfclient_toml(instance: &str) -> PathBuf { + config_base().join(format!("{}/", instance)).join("tfclient.toml") } -pub fn get_config_file(instance: &str) -> Option { - get_config_dir(instance).map(|f| f.join("tfclient.toml")) +pub fn tfdata_toml(instance: &str) -> PathBuf { + config_base().join(format!("{}/", instance)).join("tfdata.toml") } -pub fn get_cdata_dir(instance: &str) -> Option { - dirs::config_dir().map(|f| f.join("tfclient_data/").join(format!("{}/", instance))) -} - -pub fn get_cdata_file(instance: &str) -> Option { - get_cdata_dir(instance).map(|f| f.join("tfclient.toml")) -} - -pub fn get_nebulaconfig_file(instance: &str) -> Option { - get_cdata_dir(instance).map(|f| f.join("nebula.sk_embedded.yml")) -} +pub fn nebula_yml(instance: &str) -> PathBuf { + config_base().join(format!("{}/", instance)).join("nebula.yml") +} \ No newline at end of file diff --git a/tfclient/src/embedded_nebula.rs b/tfclient/src/embedded_nebula.rs deleted file mode 100644 index d48c4aa..0000000 --- a/tfclient/src/embedded_nebula.rs +++ /dev/null @@ -1,115 +0,0 @@ -use crate::dirs::get_data_dir; -use crate::util::sha256; -use log::debug; -use std::error::Error; -use std::fs; -use std::fs::File; -use std::io::Write; -use std::os::unix::fs::PermissionsExt; -use std::path::PathBuf; -use std::process::{Child, Command}; - -pub fn extract_embedded_nebula() -> Result> { - let data_dir = get_data_dir().ok_or("Unable to get platform-specific data dir")?; - if !data_dir.exists() { - fs::create_dir_all(&data_dir)?; - debug!("Created data directory {}", data_dir.as_path().display()); - } - - let bin_dir = data_dir.join("cache/"); - let hash_dir = bin_dir.join(format!("{}/", sha256(crate::nebula_bin::NEBULA_BIN))); - - if !hash_dir.exists() { - fs::create_dir_all(&hash_dir)?; - debug!("Created directory {}", hash_dir.as_path().display()); - } - - let executable_postfix = if cfg!(windows) { ".exe" } else { "" }; - let executable_name = format!( - "nebula-{}{}", - crate::nebula_bin::NEBULA_VERSION, - executable_postfix - ); - - let file_path = hash_dir.join(executable_name); - - if file_path.exists() { - // Already extracted - return Ok(file_path); - } - let mut file = File::create(&file_path)?; - file.write_all(crate::nebula_bin::NEBULA_BIN)?; - - debug!("Extracted nebula to {}", file_path.as_path().display()); - - Ok(file_path) -} - -pub fn extract_embedded_nebula_cert() -> Result> { - let data_dir = get_data_dir().ok_or("Unable to get platform-specific data dir")?; - if !data_dir.exists() { - fs::create_dir_all(&data_dir)?; - debug!("Created data directory {}", data_dir.as_path().display()); - } - - let bin_dir = data_dir.join("cache/"); - let hash_dir = bin_dir.join(format!( - "{}/", - sha256(crate::nebula_cert_bin::NEBULA_CERT_BIN) - )); - - if !hash_dir.exists() { - fs::create_dir_all(&hash_dir)?; - debug!("Created directory {}", hash_dir.as_path().display()); - } - - let executable_postfix = if cfg!(windows) { ".exe" } else { "" }; - let executable_name = format!( - "nebula-cert-{}{}", - crate::nebula_cert_bin::NEBULA_CERT_VERSION, - executable_postfix - ); - - let file_path = hash_dir.join(executable_name); - - if file_path.exists() { - // Already extracted - return Ok(file_path); - } - - let mut file = File::create(&file_path)?; - file.write_all(crate::nebula_cert_bin::NEBULA_CERT_BIN)?; - - debug!("Extracted nebula-cert to {}", file_path.as_path().display()); - - Ok(file_path) -} - -#[cfg(unix)] -pub fn _setup_permissions(path: &PathBuf) -> Result<(), Box> { - let meta = path.metadata()?; - let mut perms = meta.permissions(); - perms.set_mode(0o0755); - debug!("Setting permissions on {} to 755", path.as_path().display()); - fs::set_permissions(path, perms)?; - Ok(()) -} - -#[cfg(windows)] -pub fn _setup_permissions() -> Result<(), Box> { - Ok(()) -} - -pub fn run_embedded_nebula(args: &[String]) -> Result> { - let path = extract_embedded_nebula()?; - debug!("Running {} with args {:?}", path.as_path().display(), args); - _setup_permissions(&path)?; - Ok(Command::new(path).args(args).spawn()?) -} - -pub fn run_embedded_nebula_cert(args: &[String]) -> Result> { - let path = extract_embedded_nebula_cert()?; - debug!("Running {} with args {:?}", path.as_path().display(), args); - _setup_permissions(&path)?; - Ok(Command::new(path).args(args).spawn()?) -} diff --git a/tfclient/src/main.rs b/tfclient/src/main.rs index 4d1bac6..51c42a0 100644 --- a/tfclient/src/main.rs +++ b/tfclient/src/main.rs @@ -18,25 +18,13 @@ pub mod apiworker; pub mod config; pub mod daemon; pub mod dirs; -pub mod embedded_nebula; pub mod nebulaworker; pub mod socketclient; pub mod socketworker; pub mod timerworker; pub mod util; -pub mod nebula_bin { - include!(concat!(env!("OUT_DIR"), "/nebula.bin.rs")); -} -pub mod nebula_cert_bin { - include!(concat!(env!("OUT_DIR"), "/nebula_cert.bin.rs")); -} - -use std::fs; - use crate::config::load_config; -use crate::dirs::get_data_dir; -use crate::embedded_nebula::{run_embedded_nebula, run_embedded_nebula_cert}; use clap::{ArgAction, Parser, Subcommand}; use log::{error, info}; use simple_logger::SimpleLogger; @@ -56,20 +44,6 @@ struct Cli { #[derive(Subcommand)] enum Commands { - /// Run the `nebula` binary. This is useful if you want to do debugging with tfclient's internal nebula. - RunNebula { - /// Arguments to pass to the `nebula` binary - #[clap(trailing_var_arg = true, allow_hyphen_values = true)] - args: Vec, - }, - /// Run the `nebula-cert` binary. This is useful if you want to mess with certificates. Note: tfclient does not actually use nebula-cert for certificate operations, and instead uses trifid-pki internally - RunNebulaCert { - /// Arguments to pass to the `nebula-cert` binary - #[clap(trailing_var_arg = true, allow_hyphen_values = true)] - args: Vec, - }, - /// Clear any cached data that tfclient may have added - ClearCache {}, /// Run the tfclient daemon in the foreground Run { @@ -109,77 +83,6 @@ fn main() { } match args.subcommand { - Commands::RunNebula { args } => match run_embedded_nebula(&args) { - Ok(mut c) => match c.wait() { - Ok(stat) => match stat.code() { - Some(code) => { - if code != 0 { - error!("Nebula process exited with nonzero status code {}", code); - } - std::process::exit(code); - } - None => { - info!("Nebula process terminated by signal"); - std::process::exit(0); - } - }, - Err(e) => { - error!("Unable to wait for child to exit: {}", e); - std::process::exit(1); - } - }, - Err(e) => { - error!("Unable to start nebula binary: {}", e); - std::process::exit(1); - } - }, - Commands::ClearCache { .. } => { - let data_dir = match get_data_dir() { - Some(dir) => dir, - None => { - error!("Unable to get platform-specific data dir"); - std::process::exit(1); - } - }; - match fs::remove_dir_all(&data_dir) { - Ok(_) => (), - Err(e) => { - error!("Unable to delete data dir: {}", e); - std::process::exit(0); - } - } - info!("Removed data dir {}", data_dir.as_path().display()); - - info!("Removed all cached data."); - std::process::exit(0); - } - Commands::RunNebulaCert { args } => match run_embedded_nebula_cert(&args) { - Ok(mut c) => match c.wait() { - Ok(stat) => match stat.code() { - Some(code) => { - if code != 0 { - error!( - "nebula-cert process exited with nonzero status code {}", - code - ); - } - std::process::exit(code); - } - None => { - info!("nebula-cert process terminated by signal"); - std::process::exit(0); - } - }, - Err(e) => { - error!("Unable to wait for child to exit: {}", e); - std::process::exit(1); - } - }, - Err(e) => { - error!("Unable to start nebula-cert binary: {}", e); - std::process::exit(1); - } - }, Commands::Run { name, server } => { daemon::daemon_main(name, server); } @@ -222,10 +125,8 @@ fn main() { fn print_version() { println!( - "tfclient v{} linked to trifid-pki v{}, embedding nebula v{} and nebula-cert v{}", + "tfclient v{} linked to trifid-pki v{}", env!("CARGO_PKG_VERSION"), - trifid_pki::TRIFID_PKI_VERSION, - crate::nebula_bin::NEBULA_VERSION, - crate::nebula_cert_bin::NEBULA_CERT_VERSION + trifid_pki::TRIFID_PKI_VERSION ); } diff --git a/tfclient/src/nebulaworker.rs b/tfclient/src/nebulaworker.rs index ead052c..8218db3 100644 --- a/tfclient/src/nebulaworker.rs +++ b/tfclient/src/nebulaworker.rs @@ -2,13 +2,13 @@ use crate::config::{load_cdata, NebulaConfig, TFClientConfig}; use crate::daemon::ThreadMessageSender; -use crate::dirs::get_nebulaconfig_file; -use crate::embedded_nebula::run_embedded_nebula; +use crate::dirs::{nebula_yml}; use log::{debug, error, info}; use std::error::Error; use std::fs; use std::sync::mpsc::Receiver; -use std::time::{Duration, SystemTime}; +use nebula_ffi::NebulaInstance; +use crate::util::shutdown; pub enum NebulaWorkerMessage { Shutdown, @@ -17,17 +17,14 @@ pub enum NebulaWorkerMessage { } fn insert_private_key(instance: &str) -> Result<(), Box> { - if !get_nebulaconfig_file(instance) - .ok_or("Could not get config file location")? - .exists() - { + if !nebula_yml(instance).exists() { return Ok(()); // cant insert private key into a file that does not exist - BUT. we can gracefully handle nebula crashing - we cannot gracefully handle this fn failing } let cdata = load_cdata(instance)?; let key = cdata.dh_privkey.ok_or("Missing private key")?; let config_str = fs::read_to_string( - get_nebulaconfig_file(instance).ok_or("Could not get config file location")?, + nebula_yml(instance), )?; let mut config: NebulaConfig = serde_yaml::from_str(&config_str)?; @@ -37,7 +34,7 @@ fn insert_private_key(instance: &str) -> Result<(), Box> { let config_str = serde_yaml::to_string(&config)?; fs::write( - get_nebulaconfig_file(instance).ok_or("Could not get config file location")?, + nebula_yml(instance), config_str, )?; @@ -47,10 +44,10 @@ fn insert_private_key(instance: &str) -> Result<(), Box> { pub fn nebulaworker_main( _config: TFClientConfig, instance: String, - _transmitter: ThreadMessageSender, + transmitter: ThreadMessageSender, rx: Receiver, ) { - let _cdata = match load_cdata(&instance) { + let cdata = match load_cdata(&instance) { Ok(data) => data, Err(e) => { error!("unable to load cdata: {}", e); @@ -70,50 +67,41 @@ pub fn nebulaworker_main( return; } } - info!("starting nebula child..."); - let mut child = match run_embedded_nebula(&[ - "-config".to_string(), - get_nebulaconfig_file(&instance) - .unwrap() - .to_str() - .unwrap() - .to_string(), - ]) { - Ok(c) => c, - Err(e) => { - error!("unable to start embedded nebula binary: {}", e); - error!("nebula thread exiting with error"); - return; - } - }; - info!("nebula process started"); - let mut last_restart_time = SystemTime::now(); + let mut nebula: Option = None; - // dont need to save it, because we do not, in any circumstance, write to it - loop { - if let Ok(e) = child.try_wait() { - if e.is_some() && SystemTime::now() > last_restart_time + Duration::from_secs(5) { - info!("nebula process has exited, restarting"); - child = match run_embedded_nebula(&[ - "-config".to_string(), - get_nebulaconfig_file(&instance) - .unwrap() - .to_str() - .unwrap() - .to_string(), - ]) { - Ok(c) => c, + if cdata.creds.is_none() { + error!("not enrolled, cannot start nebula"); + } else { + info!("setting up nebula..."); + nebula = Some(match NebulaInstance::new(nebula_yml(&instance).as_path(), false) { + Ok(i) => { + info!("nebula setup"); + info!("starting nebula..."); + match i.start() { + Ok(_) => (), Err(e) => { - error!("unable to start embedded nebula binary: {}", e); + error!("error starting Nebula: {}", e); error!("nebula thread exiting with error"); + shutdown(&transmitter); return; } - }; - info!("nebula process started"); - last_restart_time = SystemTime::now(); + } + + i + }, + Err(e) => { + error!("error setting up Nebula: {}", e); + error!("nebula thread exiting with error"); + shutdown(&transmitter); + return; } - } + + }); + info!("nebula process started"); + } + + loop { match rx.recv() { Ok(msg) => match msg { NebulaWorkerMessage::WakeUp => { @@ -121,29 +109,25 @@ pub fn nebulaworker_main( } NebulaWorkerMessage::Shutdown => { info!("recv on command socket: shutdown, stopping"); - info!("shutting down nebula binary"); - match child.kill() { - Ok(_) => { - debug!("nebula process exited"); - } - Err(e) => { - error!("nebula process already exited: {}", e); + info!("shutting down nebula"); + + if let Some(i) = nebula.as_ref() { + match i.stop() { + Ok(_) => (), + Err(e) => { + error!("error stopping Nebula: {}", e); + error!("nebula thread exiting with error"); + return; + } } } + info!("nebula shut down"); break; } NebulaWorkerMessage::ConfigUpdated => { - info!("our configuration has been updated - restarting"); - debug!("killing existing process"); - match child.kill() { - Ok(_) => { - debug!("nebula process exited"); - } - Err(e) => { - error!("nebula process already exited: {}", e); - } - } + info!("our configuration has been updated - reloading"); + debug!("fixing config..."); match insert_private_key(&instance) { Ok(_) => { @@ -155,28 +139,57 @@ pub fn nebulaworker_main( return; } } - debug!("restarting nebula process"); - child = match run_embedded_nebula(&[ - "-config".to_string(), - get_nebulaconfig_file(&instance) - .unwrap() - .to_str() - .unwrap() - .to_string(), - ]) { - Ok(c) => c, - Err(e) => { - error!("unable to start embedded nebula binary: {}", e); - error!("nebula thread exiting with error"); - return; + + if let Some(i) = nebula.as_ref() { + debug!("reloading nebula"); + + match i.reload_config() { + Ok(_) => (), + Err(e) => { + error!("error reloading Nebula config: {}", e); + error!("nebula thread exiting with error"); + shutdown(&transmitter); + return; + } } - }; - last_restart_time = SystemTime::now(); - debug!("nebula process restarted"); + + debug!("config reloaded"); + } else { + debug!("detected enrollment, starting nebula for the first time"); + info!("setting up nebula..."); + nebula = Some(match NebulaInstance::new(nebula_yml(&instance).as_path(), false) { + Ok(i) => { + info!("nebula setup"); + info!("starting nebula..."); + match i.start() { + Ok(_) => (), + Err(e) => { + error!("error starting Nebula: {}", e); + error!("nebula thread exiting with error"); + shutdown(&transmitter); + return; + } + } + + i + }, + Err(e) => { + error!("error setting up Nebula: {}", e); + error!("nebula thread exiting with error"); + shutdown(&transmitter); + return; + } + + }); + info!("nebula process started"); + } + + debug!("nebula process reloaded"); } }, Err(e) => { error!("nebulaworker command socket errored: {}", e); + shutdown(&transmitter); return; } } diff --git a/tfclient/src/timerworker.rs b/tfclient/src/timerworker.rs index a747b1f..d2ff244 100644 --- a/tfclient/src/timerworker.rs +++ b/tfclient/src/timerworker.rs @@ -12,11 +12,11 @@ pub enum TimerWorkerMessage { Shutdown, } -pub fn timer_main(tx: ThreadMessageSender, rx: Receiver) { +pub fn timer_main(tx: ThreadMessageSender, rx: Receiver, disable_config_updates: bool) { let mut api_reload_timer = SystemTime::now().add(Duration::from_secs(60)); loop { - thread::sleep(Duration::from_secs(10)); + thread::sleep(Duration::from_secs(3)); match rx.try_recv() { Ok(msg) => match msg { @@ -34,7 +34,7 @@ pub fn timer_main(tx: ThreadMessageSender, rx: Receiver) { }, } - if SystemTime::now().gt(&api_reload_timer) { + if SystemTime::now().gt(&api_reload_timer) && !disable_config_updates { info!("Timer triggered: API_RELOAD_TIMER"); api_reload_timer = SystemTime::now().add(Duration::from_secs(60)); match tx.api_thread.send(APIWorkerMessage::Timer) { diff --git a/tfclient/src/util.rs b/tfclient/src/util.rs index 3176447..9c8bffe 100644 --- a/tfclient/src/util.rs +++ b/tfclient/src/util.rs @@ -2,6 +2,11 @@ use log::{error, warn}; use sha2::Digest; use sha2::Sha256; use url::Url; +use crate::apiworker::APIWorkerMessage; +use crate::daemon::ThreadMessageSender; +use crate::nebulaworker::NebulaWorkerMessage; +use crate::socketworker::SocketWorkerMessage; +use crate::timerworker::TimerWorkerMessage; pub fn sha256(bytes: &[u8]) -> String { let mut hasher = Sha256::new(); @@ -32,3 +37,51 @@ pub fn check_server_url(server: &str) { } } } + +pub fn shutdown(transmitter: &ThreadMessageSender) { + match transmitter + .nebula_thread + .send(NebulaWorkerMessage::Shutdown) + { + Ok(_) => (), + Err(e) => { + error!( + "Error sending shutdown message to nebula worker thread: {}", + e + ); + } + } + match transmitter + .api_thread + .send(APIWorkerMessage::Shutdown) + { + Ok(_) => (), + Err(e) => { + error!("Error sending shutdown message to api worker thread: {}", e); + } + } + match transmitter + .socket_thread + .send(SocketWorkerMessage::Shutdown) + { + Ok(_) => (), + Err(e) => { + error!( + "Error sending shutdown message to socket worker thread: {}", + e + ); + } + } + match transmitter + .timer_thread + .send(TimerWorkerMessage::Shutdown) + { + Ok(_) => (), + Err(e) => { + error!( + "Error sending shutdown message to timer worker thread: {}", + e + ); + } + } +} \ No newline at end of file