diff --git a/Cargo.lock b/Cargo.lock index bb9862f..240aeff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,1376 +1,1249 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "addr2line" version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] name = "adler2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6680de5231bd6ee4c6191b8a1325daa282b415391ec9d3a37bd34f2060dc73fa" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.59.0", -] - [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" dependencies = [ "axum-core", "bytes", "form_urlencoded", "futures-util", "http", "http-body", "http-body-util", "hyper", "hyper-util", "itoa", "matchit", "memchr", "mime", "percent-encoding", "pin-project-lite", "rustversion", "serde", "serde_json", "serde_path_to_error", "serde_urlencoded", "sync_wrapper", "tokio", "tower", "tower-layer", "tower-service", "tracing", ] [[package]] name = "axum-core" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" dependencies = [ "bytes", "futures-core", "http", "http-body", "http-body-util", "mime", "pin-project-lite", "rustversion", "sync_wrapper", "tower-layer", "tower-service", "tracing", ] [[package]] name = "backtrace" version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", "windows-targets 0.52.6", ] [[package]] name = "bindgen" version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ "bitflags 2.9.1", "cexpr", "clang-sys", "itertools", "log", "prettyplease", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", "syn", ] [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "clang-sys" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", "libloading", ] [[package]] name = "collar" version = "0.1.0" dependencies = [ "axum", - "bindgen", - "env_logger", - "errno", "libc", "log", + "ng", "nix", "sled", - "socket2", "thiserror", "tokio", "tower-http", "tracing", "tracing-subscriber", ] -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - [[package]] name = "crc32fast" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" -[[package]] -name = "env_filter" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "jiff", - "log", -] - [[package]] name = "errno" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", "windows-sys 0.59.0", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "fs2" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" dependencies = [ "libc", "winapi", ] [[package]] name = "futures-channel" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", ] [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-task" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-task", "pin-project-lite", "pin-utils", ] [[package]] name = "fxhash" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" dependencies = [ "byteorder", ] [[package]] name = "gimli" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "http" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", "itoa", ] [[package]] name = "http-body" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", ] [[package]] name = "http-body-util" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", "http", "http-body", "pin-project-lite", ] [[package]] name = "httparse" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", "futures-util", "http", "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", "smallvec", "tokio", ] [[package]] name = "hyper-util" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" dependencies = [ "bytes", "futures-core", "http", "http-body", "hyper", "pin-project-lite", "tokio", "tower-service", ] [[package]] name = "instant" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - [[package]] name = "itertools" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -[[package]] -name = "jiff" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" -dependencies = [ - "jiff-static", - "log", - "portable-atomic", - "portable-atomic-util", - "serde", -] - -[[package]] -name = "jiff-static" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libloading" version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", "windows-targets 0.53.0", ] [[package]] name = "lock_api" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "matchers" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ "regex-automata 0.1.10", ] [[package]] name = "matchit" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] [[package]] name = "mime" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] [[package]] name = "mio" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "wasi", "windows-sys 0.59.0", ] +[[package]] +name = "ng" +version = "0.1.0" +dependencies = [ + "bindgen", + "errno", + "libc", + "log", + "socket2", + "thiserror", +] + [[package]] name = "nix" version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ "bitflags 2.9.1", "cfg-if", "cfg_aliases", "libc", "memoffset", ] [[package]] name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", ] [[package]] name = "nu-ansi-term" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ "overload", "winapi", ] [[package]] name = "object" version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" -[[package]] -name = "once_cell_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" - [[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "parking_lot" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", "parking_lot_core 0.8.6", ] [[package]] name = "parking_lot" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core 0.9.11", ] [[package]] name = "parking_lot_core" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ "cfg-if", "instant", "libc", "redox_syscall 0.2.16", "smallvec", "winapi", ] [[package]] name = "parking_lot_core" version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", "redox_syscall 0.5.12", "smallvec", "windows-targets 0.52.6", ] [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "portable-atomic" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" - -[[package]] -name = "portable-atomic-util" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" -dependencies = [ - "portable-atomic", -] - [[package]] name = "prettyplease" version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" dependencies = [ "proc-macro2", "syn", ] [[package]] name = "proc-macro2" version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_syscall" version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ "bitflags 2.9.1", ] [[package]] name = "regex" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", "regex-automata 0.4.9", "regex-syntax 0.8.5", ] [[package]] name = "regex-automata" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ "regex-syntax 0.6.29", ] [[package]] name = "regex-automata" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", "regex-syntax 0.8.5", ] [[package]] name = "regex-syntax" version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustversion" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "serde_path_to_error" version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" dependencies = [ "itoa", "serde", ] [[package]] name = "serde_urlencoded" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", "itoa", "ryu", "serde", ] [[package]] name = "sharded-slab" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] [[package]] name = "sled" version = "0.34.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935" dependencies = [ "crc32fast", "crossbeam-epoch", "crossbeam-utils", "fs2", "fxhash", "libc", "log", "parking_lot 0.11.2", ] [[package]] name = "smallvec" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "socket2" version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "syn" version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "sync_wrapper" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" [[package]] name = "thiserror" version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "thread_local" version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", ] [[package]] name = "tokio" version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", "libc", "mio", "parking_lot 0.12.4", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tower" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", "pin-project-lite", "sync_wrapper", "tokio", "tower-layer", "tower-service", "tracing", ] [[package]] name = "tower-http" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" dependencies = [ "bitflags 2.9.1", "bytes", "http", "http-body", "pin-project-lite", "tower-layer", "tower-service", "tracing", ] [[package]] name = "tower-layer" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tracing-core" version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", ] [[package]] name = "tracing-log" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ "log", "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", "once_cell", "regex", "sharded-slab", "smallvec", "thread_local", "tracing", "tracing-core", "tracing-log", ] [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - [[package]] name = "valuable" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] [[package]] name = "windows-targets" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" dependencies = [ "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", "windows_i686_gnullvm 0.53.0", "windows_i686_msvc 0.53.0", "windows_x86_64_gnu 0.53.0", "windows_x86_64_gnullvm 0.53.0", "windows_x86_64_msvc 0.53.0", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" diff --git a/Cargo.toml b/Cargo.toml index 4e85c5d..0c7623c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,26 +1,26 @@ [package] name = "collar" version = "0.1.0" edition = "2024" [[bin]] name = "collar-ng" path = "src/bin/collar-ng.rs" +[workspace] +members = ["crates/*"] + [dependencies] -errno = "*" -socket2 = "*" +ng = { path = "crates/ng" } libc = "*" log = "0.4.27" -env_logger = "0.11.8" nix = { version = "0.30.1", features = ["ioctl", "net"] } thiserror = "2.0.12" tokio = { version = "1.45.1", features = ["full"] } axum = "0.8.4" tracing = "0.1.41" tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } tower-http = { version = "0.6.4", features = ["trace"] } sled = "0.34.7" [build-dependencies] -bindgen = "0.71.1" diff --git a/README.md b/README.md new file mode 100644 index 0000000..e99d99b --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# collar + +this is some kind of tool to manage jails. + + + +todo: +- [ ] netgraph utilities + - [x] create eiface + - [x] create bridge + - [x] join bridge +- [ ] iface utilities + - [x] rename + - [x] mtu + - [x] descr + - [ ] mac + - [ ] inet + - [ ] inet6 + - [x] enable + - [x] disable diff --git a/crates/ng/Cargo.toml b/crates/ng/Cargo.toml new file mode 100644 index 0000000..b10389d --- /dev/null +++ b/crates/ng/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "ng" +version = "0.1.0" +edition = "2024" + +[dependencies] +errno = "*" +socket2 = "*" +libc = "*" +log = "0.4.27" +thiserror = "2.0.12" + +[build-dependencies] +bindgen = "0.71.1" diff --git a/crates/ng/LICENSE b/crates/ng/LICENSE new file mode 100644 index 0000000..174b1bc --- /dev/null +++ b/crates/ng/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022, Jan-willem De Bleser +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/crates/ng/README.md b/crates/ng/README.md new file mode 100644 index 0000000..267730a --- /dev/null +++ b/crates/ng/README.md @@ -0,0 +1,4 @@ +# ngctl-rs +Rust tool for manipulating the FreeBSD Netgraph. + +This started as a tool for easily creating new ng_eiface nodes conneced to a named ng_bridge, for use as part of a custom jail setup with networking provided via Netgraph. Bindgen is used to wrap the Netgraph API, and and Rust wrappers have been written for part of the API. Given a Netgraph path, the tool will check that it is a bridge, find the first available link# hook, attach a new ng_eiface's ether hook to it, and return the interface name of the new ng_eiface. This interface can then be given to a jail via vnet, optionally renaming the interface and/or node for convenience. diff --git a/build.rs b/crates/ng/build.rs similarity index 87% rename from build.rs rename to crates/ng/build.rs index 9e20d8f..62ad211 100644 --- a/build.rs +++ b/crates/ng/build.rs @@ -1,34 +1,34 @@ extern crate bindgen; use std::env; use std::path::PathBuf; fn main() { // Tell cargo to tell rustc to link the system bzip2 // shared library. println!("cargo:rustc-link-lib=netgraph"); // Tell cargo to invalidate the built crate whenever the wrapper changes - println!("cargo:rerun-if-changed=src/ng/wrapper.h"); + println!("cargo:rerun-if-changed=src/wrapper.h"); // The bindgen::Builder is the main entry point // to bindgen, and lets you build up options for // the resulting bindings. let bindings = bindgen::Builder::default() // The input header we would like to generate // bindings for. - .header("src/ng/wrapper.h") + .header("src/wrapper.h") // Tell cargo to invalidate the built crate whenever any of the // included header files changed. .parse_callbacks(Box::new(bindgen::CargoCallbacks)) // Finish the builder and generate the bindings. .generate() // Unwrap the Result and panic on failure. .expect("Unable to generate bindings"); // Write the bindings to the $OUT_DIR/bindings.rs file. let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); bindings - .write_to_file(out_path.join("netgraph_bindings.rs")) + .write_to_file(out_path.join("bindings.rs")) .expect("Couldn't write bindings!"); } diff --git a/src/error.rs b/crates/ng/src/error.rs similarity index 74% copy from src/error.rs copy to crates/ng/src/error.rs index d8757f9..16e626b 100644 --- a/src/error.rs +++ b/crates/ng/src/error.rs @@ -1,56 +1,41 @@ #[derive(thiserror::Error, Debug)] pub enum Error { #[error("sys err")] SystemError(errno::Errno), #[error("not a bridge")] PathIsNotABridge, #[error("invalid node type")] InvalidNodeType(String, String), #[error("bridge already exists")] BridgeLinkExists(String, String), #[error("utf8")] InvalidUtf8(std::str::Utf8Error), #[error("nul")] NulError(String), #[error("exists")] Exists, #[error("invalid file descriptor")] InvalidDescriptor, - #[error("name too long")] - NameTooLong, - - #[error("description too long")] - DescriptionTooLong, - - #[error("interface not found")] - InterfaceNotFound, - - #[error("out of memory")] - OutOfMemory, - #[error("operation not supported")] NotSupported, - #[error("join error")] - TaskJoin(#[from] tokio::task::JoinError), - #[error(transparent)] Io(#[from] std::io::Error), #[error(transparent)] Nul(#[from] std::ffi::NulError), #[error(transparent)] ParseNum(#[from] std::num::ParseIntError), } pub type Result = ::std::result::Result; diff --git a/src/ng/mod.rs b/crates/ng/src/lib.rs similarity index 92% rename from src/ng/mod.rs rename to crates/ng/src/lib.rs index f06a5c0..2e2822e 100644 --- a/src/ng/mod.rs +++ b/crates/ng/src/lib.rs @@ -1,460 +1,473 @@ #![allow(non_upper_case_globals)] #![allow(non_camel_case_types)] #![allow(non_snake_case)] use errno::{Errno, errno}; use libc::{free, c_char, c_int, c_ulong, c_void, ENOENT}; use socket2::Socket; use std::{ alloc::{alloc, dealloc, Layout}, convert::TryFrom, ffi::{CString, CStr}, mem::size_of, os::unix::io::{FromRawFd, AsRawFd}, process::id, ptr, vec::Vec, }; use log::{error, debug, trace}; -use crate::{ - error::{Result, Error}, - netif, +mod error; + +pub use crate::{ + error::{Result, Error} }; -include!(concat!(env!("OUT_DIR"), "/netgraph_bindings.rs")); +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); fn copy_str_to_cchar(dst: &mut [c_char], src: &str) { for (d, s) in dst.iter_mut().zip(src.as_bytes().iter()) { *d = *s as c_char; } *(dst.last_mut().unwrap()) = 0; } impl From<(&str, &str, &str)> for ngm_mkpeer { fn from(args: (&str, &str, &str)) -> Self { let (stype, sour, speer) = args; let mut type_: [c_char; NG_TYPESIZ as usize] = [0; NG_TYPESIZ as usize]; let mut ourhook: [c_char; NG_HOOKSIZ as usize] = [0; NG_HOOKSIZ as usize]; let mut peerhook: [c_char; NG_HOOKSIZ as usize] = [0; NG_HOOKSIZ as usize]; copy_str_to_cchar(&mut type_, &stype); copy_str_to_cchar(&mut ourhook, &sour); copy_str_to_cchar(&mut peerhook, &speer); ngm_mkpeer { type_, ourhook, peerhook } } } impl From<&str> for ngm_name { fn from(name_str: &str) -> Self { let mut name: [c_char; 32] = [0; 32]; copy_str_to_cchar(&mut name, name_str); ngm_name { name } } } impl From<(&str, &str, &str)> for ngm_connect { fn from(args: (&str, &str, &str)) -> Self { let (spath, sour, speer) = args; let mut path: [c_char; NG_PATHSIZ as usize] = [0; NG_PATHSIZ as usize]; let mut ourhook: [c_char; NG_HOOKSIZ as usize] = [0; NG_HOOKSIZ as usize]; let mut peerhook: [c_char; NG_HOOKSIZ as usize] = [0; NG_HOOKSIZ as usize]; copy_str_to_cchar(&mut path, &spath); copy_str_to_cchar(&mut ourhook, &sour); copy_str_to_cchar(&mut peerhook, &speer); ngm_connect { path, ourhook, peerhook } } } type ControlSocket = Socket; type DataSocket = Socket; #[allow(dead_code)] #[derive(Debug)] struct NodeInfo { name: String, nodetype: String, id: u32, hooks: u32 } impl TryFrom for NodeInfo { type Error = Error; fn try_from(ninf: nodeinfo) -> Result { let name = unsafe{CStr::from_ptr(ninf.name.as_ptr())}.to_str().map_err(Error::InvalidUtf8)?.to_owned(); let type_ = unsafe{CStr::from_ptr(ninf.type_.as_ptr())}.to_str().map_err(Error::InvalidUtf8)?.to_owned(); Ok(NodeInfo { name: name, nodetype: type_, id: ninf.id, hooks: ninf.hooks }) } } #[allow(dead_code)] #[derive(Debug)] struct LinkInfo { ourhook: String, peerhook: String, peer: NodeInfo } impl TryFrom<&linkinfo> for LinkInfo { type Error = Error; fn try_from(linf: &linkinfo) -> Result { let ourhook = unsafe{CStr::from_ptr(linf.ourhook.as_ptr())}.to_str().map_err(Error::InvalidUtf8)?.to_owned(); let peerhook = unsafe{CStr::from_ptr(linf.peerhook.as_ptr())}.to_str().map_err(Error::InvalidUtf8)?.to_owned(); let peer = NodeInfo::try_from(linf.nodeinfo)?; Ok(LinkInfo { ourhook, peerhook, peer }) } } fn ng_mk_sock_node(name: String) -> Result<(ControlSocket, DataSocket), Errno> { let c_str = CString::new(name).unwrap(); let mut csp: c_int = 0; let mut dsp: c_int = 0; let pcsp: *mut c_int = &mut csp; let pdsp: *mut c_int = &mut dsp; let ret = unsafe { NgMkSockNode(c_str.as_ptr() as *const c_char, pcsp, pdsp) }; if ret == -1 { return Err(errno()) } Ok(unsafe { (Socket::from_raw_fd(csp), Socket::from_raw_fd(dsp)) }) } unsafe fn ng_alloc_recv_msg(csock: &ControlSocket) -> Result<(*mut ng_mesg, CString), Errno> { let cs: c_int = csock.as_raw_fd(); let mut respptr: *mut ng_mesg = ptr::null_mut(); let pathlayout = Layout::from_size_align(NG_PATHSIZ as usize, 1).unwrap(); let pathbuf = unsafe { alloc(pathlayout) as *mut c_char }; let ret = unsafe { NgAllocRecvMsg(cs, &mut respptr, pathbuf) }; let resppath = unsafe { CStr::from_ptr(pathbuf).to_owned() }; unsafe { dealloc(pathbuf as *mut u8, pathlayout) }; if ret == -1 { return Err(errno()) } Ok((respptr, resppath)) } unsafe fn ng_send_msg(csock: &ControlSocket, path: &CStr, cookie: c_int, cmd: c_int, parg: *const c_void, arglen: c_ulong) -> Result<(), Errno> { let ret = unsafe { NgSendMsg(csock.as_raw_fd(), path.as_ptr() as *const c_char, cookie, cmd, parg, arglen.try_into().unwrap()) }; if ret == -1 { return Err(errno()) } Ok(()) } unsafe fn ng_send_ascii_message(csock: &ControlSocket, path: &CStr, query: &CStr) -> Result<(), Errno> { // FIXME multiple arguments in let ret = unsafe { NgSendAsciiMsg(csock.as_raw_fd(), path.as_ptr() as *const c_char, query.as_ptr() as *const c_char) }; if ret == -1 { return Err(errno()) } Ok(()) } fn command_response(csock: &ControlSocket, path: &str, cookie: c_int, cmd: c_int, parg: *const c_void, arglen: c_ulong) -> Result<*mut ng_mesg, Error> { let cpath = CString::new(path).map_err(|_| Error::NulError(path.to_owned()))?; Ok(unsafe { ng_send_msg(csock, &cpath, cookie, cmd, parg, arglen).map_err(Error::SystemError)?; let (msg, _) = ng_alloc_recv_msg(csock).map_err(Error::SystemError)?; msg }) } fn list_hooks(csock: &ControlSocket, path: &str) -> Result<(NodeInfo, Vec), Error> { let parg: *const c_void = ptr::null(); let respptr: *mut ng_mesg = command_response(csock, path, NGM_GENERIC_COOKIE as c_int, NGM_LISTHOOKS as c_int, parg, 0)?; // Pointer should not be null at this point (check?) Ok(unsafe { let pdata: *const hooklist = (*respptr).data.as_ptr().cast(); let ninf = NodeInfo::try_from((*pdata).nodeinfo)?; let tmp: Result, Error> = (*pdata) .link .as_slice(ninf.hooks.try_into().unwrap()) .iter() .map(|l| LinkInfo::try_from(l)) .collect(); let mut links = tmp?; links.sort_unstable_by(|a, b| a.ourhook.cmp(&b.ourhook)); // ng_mesg is a nested set of flexible-array structs, so one call to free() is enough free(respptr as *mut c_void); (ninf, links) }) } fn find_free_hook(csock: &ControlSocket, path: &str) -> Result { let (ninf, links) = list_hooks(csock, path)?; if ninf.nodetype != "bridge" { return Err(Error::PathIsNotABridge); } for (n, l) in links.iter().map(|l| l.ourhook[4..].parse::().unwrap()).enumerate() { if l > n.try_into().unwrap() { return Ok(n) } } Ok(ninf.hooks.try_into().unwrap()) } fn make_peer(csock: &ControlSocket, path: &str, nodetype: &str, ourhook: &str, peerhook: &str) -> Result<(), Error> { let cpath = CString::new(path).map_err(|_| Error::NulError(path.to_owned()))?; let newpeer = ngm_mkpeer::from((nodetype, ourhook, peerhook)); let pnewpeer: *const ngm_mkpeer = &newpeer; trace!("make_peer {} {} {} {}", path, nodetype, ourhook, peerhook); // send the makepeer command unsafe { ng_send_msg(csock, &cpath, NGM_GENERIC_COOKIE as c_int, NGM_MKPEER as c_int, pnewpeer as *const c_void, size_of::() as u64).map_err(Error::SystemError)? }; // no response expected Ok(()) } fn connect_nodes(csock: &ControlSocket, from_path: &str, to_path: &str, ourhook: &str, peerhook: &str) -> Result<(), Error> { let cfrom_path = CString::new(from_path).map_err(|_| Error::NulError(from_path.to_owned()))?; let connect_msg = ngm_connect::from((to_path, ourhook, peerhook)); let pconnect_msg: *const ngm_connect = &connect_msg; trace!("connect_nodes {} {} {} {}", from_path, to_path, ourhook, peerhook); // send the connect command unsafe { ng_send_msg(csock, &cfrom_path, NGM_GENERIC_COOKIE as c_int, NGM_CONNECT as c_int, pconnect_msg as *const c_void, size_of::() as u64).map_err(Error::SystemError)? }; // no response expected Ok(()) } fn get_interface_name(csock: &ControlSocket, iface: &str) -> Result { let linkpath = format!("{}:", iface); //String::from(path); // already contains a colon at the end let clpath = CString::new(linkpath.clone()).map_err(|_| Error::NulError(linkpath))?; let query = CString::new("getifname").unwrap(); // this should never fail unsafe { ng_send_ascii_message(csock, &clpath, &query).map_err(Error::SystemError)?; let (binresp, _) = ng_alloc_recv_msg(csock).map_err(Error::SystemError)?; let text: *const c_char = (*binresp).data.as_ptr().cast(); let device_name = CStr::from_ptr(text).to_owned(); free(binresp as *mut c_void); Ok(device_name) } } fn get_interface_name_from_path(csock: &ControlSocket, path: &str, ourhook: &str) -> Result { let mut linkpath = String::from(path); // already contains a colon at the end linkpath.push_str(&ourhook); let clpath = CString::new(linkpath.clone()).map_err(|_| Error::NulError(linkpath))?; let query = CString::new("getifname").unwrap(); // this should never fail unsafe { ng_send_ascii_message(csock, &clpath, &query).map_err(Error::SystemError)?; let (binresp, _) = ng_alloc_recv_msg(csock).map_err(Error::SystemError)?; let text: *const c_char = (*binresp).data.as_ptr().cast(); let device_name = CStr::from_ptr(text).to_owned(); free(binresp as *mut c_void); Ok(device_name) } } pub fn go(path: &str) -> Result { let (csock, _) = ng_mk_sock_node(format!("ngctlrs{}", id())).map_err(Error::SystemError)?; //unsafe { NgSetDebug(2) }; let link = format!("link{}", find_free_hook(&csock, path)?); make_peer(&csock, path, "eiface", &link, "ether")?; let device_name = get_interface_name_from_path(&csock, path, &link)?; Ok(device_name.into_string().map_err(|e| Error::InvalidUtf8(e.utf8_error()))?) } -pub fn post_new_eiface(csock: &ControlSocket, ng_name: &str, description: Option<&str>) -> Result<(), Error> { +/*pub fn post_new_eiface(csock: &ControlSocket, ng_name: &str, description: Option<&str>) -> Result<(), Error> { let iface_name = get_interface_name(&csock, &ng_name)?.into_string().map_err(|e| Error::InvalidUtf8(e.utf8_error()))?; debug!("ng eiface {} is iface: {}", ng_name, iface_name); let mut iface = netif::Iface::new(&iface_name)?; iface.set_name(&ng_name)?; trace!("ng eiface {} iface renamed (was {})", ng_name, iface_name); if let Some(description) = description { iface.set_description(description)?; trace!("ng eiface {} iface description set: '{}'", ng_name, description); } Ok(()) +}*/ + +#[derive(Debug)] +pub struct NewEiface { + created: bool, + name: String, + iface_name: String } -pub fn new_eiface(name: &str) -> Result { +pub fn new_eiface(name: &str) -> Result { let (csock, _) = ng_mk_sock_node(format!("ngctlrs{}", id())).map_err(Error::SystemError)?; // Check if a node with the given name already exists let name_with_colon = format!("{}:", name); let name_cstr = CString::new(name_with_colon).map_err(|_| Error::NulError(name.to_owned()))?; // Try to send NGM_NODEINFO to the named node - match unsafe { + let created = match unsafe { ng_send_msg(&csock, &name_cstr, NGM_GENERIC_COOKIE as c_int, NGM_NODEINFO as c_int, std::ptr::null(), 0) } { Ok(_) => { // Node exists, return the name - return Ok(name.to_string()); + false }, Err(e) if e.0 == ENOENT => { // Node doesn't exist, continue with creation + make_peer(&csock, ".", "eiface", "ether", "ether")?; + + // Send the name message to the newly created eiface node + let name_msg = ngm_name::from(name); + let pname_msg: *const ngm_name = &name_msg; + let cpath = CString::new(".ether").map_err(|_| Error::NulError(".ether".to_owned()))?; + + unsafe { + ng_send_msg(&csock, &cpath, NGM_GENERIC_COOKIE as c_int, NGM_NAME as c_int, + pname_msg as *const c_void, size_of::() as u64) + .map_err(Error::SystemError)? + }; + + true }, Err(e) => { // Other error, propagate it return Err(Error::SystemError(e)); } - } - - make_peer(&csock, ".", "eiface", "ether", "ether")?; - - // Send the name message to the newly created eiface node - let name_msg = ngm_name::from(name); - let pname_msg: *const ngm_name = &name_msg; - let cpath = CString::new(".ether").map_err(|_| Error::NulError(".ether".to_owned()))?; - - unsafe { - ng_send_msg(&csock, &cpath, NGM_GENERIC_COOKIE as c_int, NGM_NAME as c_int, - pname_msg as *const c_void, size_of::() as u64) - .map_err(Error::SystemError)? }; - match post_new_eiface(&csock, &name, None) { + let iface_name = get_interface_name(&csock, &name)?.into_string().map_err(|e| Error::InvalidUtf8(e.utf8_error()))?; + debug!("ng eiface (new: {}) {} is iface: {}", created, name, iface_name); + //let iface_name = "lol".to_string(); + /*match post_new_eiface(&csock, &name, None) { Ok(_) => { Ok(name.to_string()) }, Err(e) => { error!("failed to configure ngeth interface {}: {:?}", name, e); shutdown_interface(&csock, &name)?; Err(e) } - } + }*/ //Ok(device_name.into_string().map_err(|e| Error::InvalidUtf8(e.utf8_error()))?) + Ok(NewEiface { created, name: name.to_string(), iface_name }) } // TODO: Check if the interface is already bridged. pub fn bridge_eiface(bridge: &str, name: &str) -> Result { let (csock, _) = ng_mk_sock_node(format!("ngctlrs{}", id())).map_err(Error::SystemError)?; // Find a free hook on the bridge let bridge_path = format!("{}:", bridge); let link = format!("link{}", find_free_hook(&csock, &bridge_path)?); // Connect the existing eiface to the bridge let eiface_path = format!("{}:", name); connect_nodes(&csock, &bridge_path, &eiface_path, &link, "ether")?; Ok(name.to_string()) } fn is_peer(links: &Vec, peer: &str) -> bool { links.iter().any(|link| link.peer.name == peer) } fn has_hook(links: &Vec, ourhook: &str) -> bool { links.iter().any(|link| link.ourhook == ourhook) } pub fn new_bridge(bridge: &str, name: &str) -> Result { let (csock, _) = ng_mk_sock_node(format!("ngctlrs{}", id())).map_err(Error::SystemError)?; match list_hooks(&csock, &format!("{}:", &name)) { Ok(_) => {}, Err(e) => { error!("interface {}: does not exists", &name); return Err(e); } } // Check if a bridge with the given name already exists let bridge_path = format!("{}:", bridge); // Try to send NGM_NODEINFO to the named bridge match list_hooks(&csock, &bridge_path) { Ok((ninf, links)) => { debug!("bridge exists: {}", &bridge); debug!("Bridge Node: {:?}", ninf); if ninf.nodetype != "bridge" { return Err(Error::InvalidNodeType(bridge.to_string(), ninf.nodetype.to_string())); } debug!("Links: {:?}", &links); if is_peer(&links, &name) { debug!("interface {} already exists on bridge {}", &name, &bridge); return Err(Error::Exists) } if has_hook(&links, "link0") { debug!("bridge {} already has a link0", &bridge); return Err(Error::BridgeLinkExists(bridge.to_string(), "link0".to_string())) } // Connect the existing eiface to the bridge debug!("connecting {} to {} as link0", &name, &bridge); let eiface_path = format!("{}:", name); connect_nodes(&csock, &bridge_path, &eiface_path, "link0", "ether")?; }, Err(Error::SystemError(e)) if e.0 == ENOENT => { // mkpeer derp: bridge ether link0 // Bridge doesn't exist, create it debug!("bridge {} does not exist", &bridge); make_peer(&csock, format!("{}:", &name).as_str(), "bridge", "ether", "link0")?; // Send the name message to the newly created bridge node trace!("naming {}:ether -> {}", &name, &bridge); let bridge_relative_path = format!("{}:ether", &name); let bridge_name_msg = ngm_name::from(bridge); let pbridge_name_msg: *const ngm_name = &bridge_name_msg; let bridge_relative_path = CString::new(bridge_relative_path.clone()).map_err(|_| Error::NulError(bridge_relative_path.clone().to_owned()))?; unsafe { ng_send_msg(&csock, &bridge_relative_path, NGM_GENERIC_COOKIE as c_int, NGM_NAME as c_int, pbridge_name_msg as *const c_void, size_of::() as u64) .map_err(Error::SystemError)? }; }, Err(e) => { // Other error, propagate it return Err(e); } } Ok(bridge.to_string()) } /// Sends a shutdown message to a named netgraph node /// /// This function sends an NGM_SHUTDOWN control message to the netgraph node /// specified by `name`. The node will be destroyed and all its hooks will /// be disconnected. /// /// # Arguments /// /// * `csock` - The control socket to send the message through /// * `name` - The name of the netgraph node to shutdown (without the colon suffix) /// /// # Returns /// /// Returns `Ok(())` if the shutdown message was sent successfully, or an `Error` /// if the message could not be sent. pub fn shutdown_interface(csock: &ControlSocket, name: &str) -> Result<(), Error> { let name_with_colon = format!("{}:", name); let name_cstr = CString::new(name_with_colon).map_err(|_| Error::NulError(name.to_owned()))?; trace!("shutdown_interface {}", name); // Send the shutdown command to the named node unsafe { ng_send_msg(csock, &name_cstr, NGM_GENERIC_COOKIE as c_int, NGM_SHUTDOWN as c_int, std::ptr::null(), 0) .map_err(Error::SystemError)? }; // No response expected for shutdown Ok(()) } diff --git a/src/ng/wrapper.h b/crates/ng/src/wrapper.h similarity index 100% rename from src/ng/wrapper.h rename to crates/ng/src/wrapper.h diff --git a/src/bin/collar-ng.rs b/src/bin/collar-ng.rs index 63030ce..e36ef5f 100644 --- a/src/bin/collar-ng.rs +++ b/src/bin/collar-ng.rs @@ -1,71 +1,69 @@ use std::env::args; use env_logger::Env; use log::error; -use collar::{ - error::{Result, Error}, - ng, -}; +use ng::error::{Result, Error}; +use ng; fn main() { let env = Env::default() .filter_or("LOG_LEVEL", "trace") .write_style_or("LOG_STYLE", "always"); env_logger::init_from_env(env); let mut argv = args(); let prog = argv.next().unwrap(); match argv.next() { None => println!("Usage: {} (args)", prog), Some(str) => match str.as_str() { "new-eiface" => { match argv.next() { None => println!("Usage: {} new-eiface ", prog), Some(name) => match ng::new_eiface(&name) { Ok(s) => println!("ok: {}", s), Err(e) => error!("error: {:?}", e), } } }, "new-eiface-bridge" => { match argv.next() { None => println!("Usage: {} new-bridge ", prog), Some(bridge) => match argv.next() { None => println!("Usage: {} new-bridge ", prog), Some(name) => match ng::new_bridge(&bridge, &name) { Ok(s) => println!("ok: {}", s), Err(e) => error!("error: {:?}", e) } } } } "join-eiface-bridge" => { match argv.next() { None => println!("Usage: {} bridge-eiface ", prog), Some(bridge) => match argv.next() { None => println!("Usage: {} bridge-eiface ", prog), Some(name) => match ng::bridge_eiface(&bridge, &name) { Ok(s) => println!("ok: {}", s), Err(e) => error!("error: {:?}", e) } } } } "bridge" => { match argv.next() { None => println!("Usage: {} ", prog), Some(path) => match ng::go(&path) { Ok(s) => println!("{}", s), Err(e) => error!("error: {:?}", e) } } } _ => println!("Unknown action: {}", str) } } } diff --git a/src/bin/collared.rs b/src/bin/collared.rs index ca76558..62580e8 100644 --- a/src/bin/collared.rs +++ b/src/bin/collared.rs @@ -1,53 +1,53 @@ use std::env::args; use tokio::net::TcpListener; use tower_http::trace::TraceLayer; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; use std::sync::Arc; use axum::{ routing::get, extract::{State, Request, Json, Path, Extension, Query}, routing::post, }; struct AppState { leash: collar::NetworkLeash, } #[tokio::main] async fn main() { tracing_subscriber::registry() .with( tracing_subscriber::filter::EnvFilter::try_from_default_env().unwrap_or_else(|_| { "collar=trace,tower_http=debug,axum::rejection=trace" .into() }), ) .with(tracing_subscriber::fmt::layer()) .init(); let leash = collar::NetworkLeash::new(); let state = Arc::new(AppState { leash }); // build our application with a single route let app = axum::Router::new() .route("/", get(|| async { "collared." })) .route("/ng/eiface/{name}", post(post_ng_eiface)) .with_state(state) .layer(tower_http::trace::TraceLayer::new_for_http()); // run our app with hyper, listening globally on port 3000 let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); tracing::info!("listening on {}", listener.local_addr().unwrap()); axum::serve(listener, app).await.unwrap(); } async fn post_ng_eiface(State(state): State>, Path(name): Path) -> Result { let fname = name.clone(); let result = state.leash.gated(move || { - collar::ng::new_eiface(&name) + Ok(ng::new_eiface(&name)) }).await; Ok(format!("sup {} => {:?}", &fname, result)) } diff --git a/src/error.rs b/src/error.rs index d8757f9..39a4a1b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,56 +1,59 @@ #[derive(thiserror::Error, Debug)] pub enum Error { - #[error("sys err")] - SystemError(errno::Errno), + //#[error("sys err")] + //SystemError(errno::Errno), #[error("not a bridge")] PathIsNotABridge, #[error("invalid node type")] InvalidNodeType(String, String), #[error("bridge already exists")] BridgeLinkExists(String, String), #[error("utf8")] InvalidUtf8(std::str::Utf8Error), #[error("nul")] NulError(String), #[error("exists")] Exists, #[error("invalid file descriptor")] InvalidDescriptor, #[error("name too long")] NameTooLong, #[error("description too long")] DescriptionTooLong, #[error("interface not found")] InterfaceNotFound, #[error("out of memory")] OutOfMemory, #[error("operation not supported")] NotSupported, + #[error(transparent)] + Netgraph(#[from] ng::Error), + #[error("join error")] TaskJoin(#[from] tokio::task::JoinError), #[error(transparent)] Io(#[from] std::io::Error), #[error(transparent)] Nul(#[from] std::ffi::NulError), #[error(transparent)] ParseNum(#[from] std::num::ParseIntError), } pub type Result = ::std::result::Result; diff --git a/src/lib.rs b/src/lib.rs index ed942eb..114f244 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,49 +1,47 @@ pub mod error; pub mod netif; -pub mod ng; - use std::sync::Arc; use tokio::sync::Mutex; use crate::error::{Error, Result}; pub struct NetworkLeash { lock: Arc> } impl NetworkLeash { pub fn new() -> Self { tracing::trace!("Creating new NetworkLeash"); Self { lock: Arc::new(Mutex::new(())), } } pub async fn with_interface(&self, name: &str, operation: F) -> Result where F: FnOnce(&mut crate::netif::Iface) -> Result + Send + 'static, R: Send + 'static, { let _guard = self.lock.lock().await; let name = name.to_string(); tokio::task::spawn_blocking(move || { let mut iface = crate::netif::Iface::new(&name)?; operation(&mut iface) }).await? } pub async fn gated(&self, operation: F) -> Result where F: FnOnce() -> Result + Send + 'static, R: Send + 'static, { let _guard = self.lock.lock().await; tokio::task::spawn_blocking(move || { operation() }).await? } }