From 04ece4cca8f48f4c38924b1fb48a6e2027e91885 Mon Sep 17 00:00:00 2001 From: asonix Date: Fri, 4 Sep 2020 22:24:04 -0500 Subject: [PATCH] Almost working port forwarding, but foiled by serde-urlencoded once again --- .gitignore | 1 + Cargo.lock | 2043 +++++++++++++++++++++++++++++++++++++++ Cargo.toml | 26 + config.toml | 8 + scss/index.scss | 0 src/build.rs | 10 + src/iptables.rs | 302 ++++++ src/main.rs | 84 ++ src/rules.rs | 148 +++ src/startup/mod.rs | 185 ++++ src/startup/preload.rs | 259 +++++ templates/rules.rs.html | 61 ++ 12 files changed, 3127 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 config.toml create mode 100644 scss/index.scss create mode 100644 src/build.rs create mode 100644 src/iptables.rs create mode 100644 src/main.rs create mode 100644 src/rules.rs create mode 100644 src/startup/mod.rs create mode 100644 src/startup/preload.rs create mode 100644 templates/rules.rs.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..363d078 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2043 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "addr2line" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" + +[[package]] +name = "aead" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7001367fde4c768a19d1029f0a8be5abd9308e1119846d5bd9ad26297b8faf5" +dependencies = [ + "aes-soft", + "aesni", + "block-cipher", +] + +[[package]] +name = "aes-gcm" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f5007801316299f922a6198d1d09a0bae95786815d066d5880d13f7c45ead1" +dependencies = [ + "aead", + "aes", + "block-cipher", + "ghash", + "subtle", +] + +[[package]] +name = "aes-soft" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4925647ee64e5056cf231608957ce7c81e12d6d6e316b9ce1404778cc1d35fa7" +dependencies = [ + "block-cipher", + "byteorder", + "opaque-debug 0.2.3", +] + +[[package]] +name = "aesni" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050d39b0b7688b3a3254394c3e30a9d66c41dcf9b05b0e2dbdc623f6505d264" +dependencies = [ + "block-cipher", + "opaque-debug 0.2.3", +] + +[[package]] +name = "aho-corasick" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" + +[[package]] +name = "arc-swap" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + +[[package]] +name = "async-channel" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21279cfaa4f47df10b1816007e738ca3747ef2ee53ffc51cdbf57a8bb266fee3" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f47c78ea98277cb1f5e6f60ba4fc762f5eafe9f6511bc2f7dfd8b75c225650" +dependencies = [ + "async-io 0.1.11", + "futures-lite 0.1.11", + "multitask", + "parking 1.0.6", + "scoped-tls", + "waker-fn", +] + +[[package]] +name = "async-h1" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca2b5cfe1804f48bb8dfb1b2391e6e9a3fbf89e07514dce3bddb03eb4d529db" +dependencies = [ + "async-std", + "byte-pool", + "futures-core", + "http-types", + "httparse", + "lazy_static", + "log", + "pin-project-lite", +] + +[[package]] +name = "async-io" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae22a338d28c75b53702b66f77979062cb29675db376d99e451af4fa79dedb3" +dependencies = [ + "cfg-if", + "concurrent-queue", + "futures-lite 0.1.11", + "libc", + "once_cell", + "parking 2.0.0", + "polling", + "socket2", + "vec-arena", + "wepoll-sys-stjepang", + "winapi", +] + +[[package]] +name = "async-io" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9424bb88867b003ca32a1d99cf64595c5a310c7322891795f38aa061860d0af" +dependencies = [ + "cfg-if", + "concurrent-queue", + "fastrand", + "futures-lite 1.0.0", + "libc", + "log", + "once_cell", + "parking 2.0.0", + "polling", + "socket2", + "vec-arena", + "waker-fn", + "wepoll-sys-stjepang", + "winapi", +] + +[[package]] +name = "async-mutex" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "065de1ccf10280d0d75c2f3a71a970ee1007c85c51aa3e7deee1df100f1dfadb" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-process" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d510baf319291a41e6c3363df4408a3b196ad18fcb1305ae4e500f2eabe260" +dependencies = [ + "async-io 0.2.7", + "blocking 0.6.1", + "cfg-if", + "event-listener", + "futures-lite 1.0.0", + "once_cell", + "signal-hook", + "winapi", +] + +[[package]] +name = "async-session" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345022a2eed092cd105cc1b26fd61c341e100bd5fcbbd792df4baf31c2cc631f" +dependencies = [ + "anyhow", + "async-std", + "async-trait", + "base64", + "bincode", + "blake3", + "chrono", + "hmac", + "kv-log-macro", + "rand", + "serde 1.0.115", + "serde_json", + "sha2", +] + +[[package]] +name = "async-sse" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "885fb340b166aff3a3b16dd49ef169d8ee34428aa10c0432c61fff584aa222b9" +dependencies = [ + "async-channel", + "async-std", + "http-types", + "log", + "memchr", + "pin-project-lite", +] + +[[package]] +name = "async-std" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c8da367da62b8ff2313c406c9ac091c1b31d67a165becdd2de380d846260f7" +dependencies = [ + "async-executor", + "async-io 0.1.11", + "async-mutex", + "async-task", + "blocking 0.5.2", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 0.1.11", + "futures-timer", + "kv-log-macro", + "log", + "memchr", + "num_cpus", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17772156ef2829aadc587461c7753af20b7e8db1529bc66855add962a3b35d3" + +[[package]] +name = "async-trait" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "687c230d85c0a52504709705fc8a53e4a692b83a2184f03dae73e38e1e93a783" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atomic-waker" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "backtrace" +version = "0.3.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base-x" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b20b618342cf9891c292c4f5ac2cde7287cc5c87e87e9c769d617793607dec1" + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "bincode" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" +dependencies = [ + "byteorder", + "serde 1.0.115", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "blake3" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce4f9586c9a3151c4b49b19e82ba163dd073614dd057e53c969e1a4db5b52720" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "crypto-mac", + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-cipher" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa136449e765dc7faa244561ccae839c394048667929af599b5d931ebe7b7f10" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blocking" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea5800d29218fea137b0880387e5948694a23c93fcdde157006966693a865c7c" +dependencies = [ + "async-channel", + "atomic-waker", + "futures-lite 0.1.11", + "once_cell", + "waker-fn", +] + +[[package]] +name = "blocking" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f30e08a950487f80d2de5cbb72772c8bbaed6002dc8d979722dabd034ede18d" +dependencies = [ + "async-channel", + "atomic-waker", + "fastrand", + "futures-lite 1.0.0", + "once_cell", + "waker-fn", +] + +[[package]] +name = "bumpalo" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" + +[[package]] +name = "byte-pool" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38e98299d518ec351ca016363e0cbfc77059dcd08dfa9700d15e405536097a" +dependencies = [ + "crossbeam-queue", + "stable_deref_trait", +] + +[[package]] +name = "bytecount" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0017894339f586ccb943b01b9555de56770c11cda818e7e3d8bd93f4ed7f46e" + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + +[[package]] +name = "cache-padded" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" + +[[package]] +name = "cc" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "chrono" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b" +dependencies = [ + "num-integer", + "num-traits 0.2.12", + "serde 1.0.115", + "time 0.1.44", +] + +[[package]] +name = "cloudabi" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" +dependencies = [ + "bitflags", +] + +[[package]] +name = "concurrent-queue" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +dependencies = [ + "cache-padded", +] + +[[package]] +name = "config" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3" +dependencies = [ + "lazy_static", + "nom", + "rust-ini", + "serde 1.0.115", + "serde-hjson", + "serde_json", + "toml", + "yaml-rust", +] + +[[package]] +name = "const_fn" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce90df4c658c62f12d78f7508cf92f9173e5184a539c10bfe54a3107b3ffd0f2" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "cookie" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1373a16a4937bc34efec7b391f9c1500c30b8478a701a4f44c9165cc0475a6e0" +dependencies = [ + "aes-gcm", + "base64", + "hkdf", + "hmac", + "percent-encoding", + "rand", + "sha2", + "time 0.2.17", + "version_check", +] + +[[package]] +name = "cpuid-bool" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" + +[[package]] +name = "crc32fast" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "maybe-uninit", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "data-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d0e2d24e5ee3b23a01de38eefdcd978907890701f08ffffd4cb457ca4ee8d6" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "dtoa" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b" + +[[package]] +name = "either" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f" + +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "backtrace", + "version_check", +] + +[[package]] +name = "event-listener" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cd41440ae7e4734bbd42302f63eaba892afc93a3912dad84006247f0dedb0e" + +[[package]] +name = "fastrand" +version = "1.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c85295147490b8fcf2ea3d104080a105a8b2c63f9c319e82c02d8e952388919" + +[[package]] +name = "femme" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af1a24f391a5a94d756db5092c6576aad494b88a71a5a36b20c67b63e0df034" +dependencies = [ + "cfg-if", + "js-sys", + "log", + "serde 1.0.115", + "serde_derive", + "serde_json", + "wasm-bindgen", + "web-sys", +] + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" + +[[package]] +name = "futures-io" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" + +[[package]] +name = "futures-lite" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97999970129b808f0ccba93211201d431fcc12d7e1ffae03a61b5cedd1a7ced2" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking 2.0.0", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd8ccee4974dccf68838bb2b9c90439238090061c82454af83866ac059eb9f" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking 2.0.0", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-task" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" +dependencies = [ + "once_cell", +] + +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +dependencies = [ + "gloo-timers", + "send_wrapper", +] + +[[package]] +name = "futures-util" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" +dependencies = [ + "futures-core", + "futures-macro", + "futures-task", + "pin-project", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "ghash" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6e27f0689a6e15944bdce7e45425efb87eaa8ab0c6e87f11d0987a9133e2531" +dependencies = [ + "polyval", +] + +[[package]] +name = "gimli" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "gloo-timers" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "hermit-abi" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +dependencies = [ + "libc", +] + +[[package]] +name = "hkdf" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe1149865383e4526a43aee8495f9a325f0b806c63ce6427d06336a590abbbc9" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest", +] + +[[package]] +name = "http-types" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4daf8dc001485f4a32a7a17c54c67fa8a10340188f30ba87ac0fe1a9451e97" +dependencies = [ + "anyhow", + "async-std", + "cookie", + "infer", + "pin-project-lite", + "rand", + "serde 1.0.115", + "serde_json", + "serde_qs", + "serde_urlencoded", + "url", +] + +[[package]] +name = "httparse" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" + +[[package]] +name = "idna" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "infer" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6854dd77ddc4f9ba1a448f487e27843583d407648150426a30c2ea3a2c39490a" + +[[package]] +name = "instant" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485" + +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" + +[[package]] +name = "jobserver" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a7e2c92a4804dd459b86c339278d0fe87cf93757fae222c3fa3ae75458bc73" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lexical-core" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if", + "ryu", + "static_assertions", +] + +[[package]] +name = "libc" +version = "0.2.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" + +[[package]] +name = "linked-hash-map" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" +dependencies = [ + "serde 0.8.23", + "serde_test", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" + +[[package]] +name = "lock_api" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" + +[[package]] +name = "memoffset" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c198b026e1bbf08a937e94c6c60f9ec4a2267f5b0d2eec9c1b21b061ce2be55f" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "miniz_oxide" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d7559a8a40d0f97e1edea3220f698f78b1c5ab67532e49f68fde3910323b722" +dependencies = [ + "adler", +] + +[[package]] +name = "multitask" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c09c35271e7dcdb5f709779111f2c8e8ab8e06c1b587c1c6a9e179d865aaa5b4" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", +] + +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "lexical-core", + "memchr", + "version_check", +] + +[[package]] +name = "num-integer" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" +dependencies = [ + "autocfg", + "num-traits 0.2.12", +] + +[[package]] +name = "num-rational" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg", + "num-integer", + "num-traits 0.2.12", +] + +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +dependencies = [ + "num-traits 0.2.12", +] + +[[package]] +name = "num-traits" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" + +[[package]] +name = "once_cell" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "parking" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb300f271742d4a2a66c01b6b2fa0c83dfebd2e0bf11addb879a3547b4ed87c" + +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + +[[package]] +name = "parking_lot" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" +dependencies = [ + "cfg-if", + "cloudabi", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca4433fff2ae79342e497d9f8ee990d174071408f28f726d6d83af93e58e48aa" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "polling" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e9fa0ab21ed700cf0c4ebec57ae5496bec942a0aef9545562979a9f75b97aa" +dependencies = [ + "cfg-if", + "libc", + "log", + "wepoll-sys-stjepang", + "winapi", +] + +[[package]] +name = "polyval" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9a50142b55ab3ed0e9f68dfb3709f1d90d29da24e91033f28b96330643107dc" +dependencies = [ + "cfg-if", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" + +[[package]] +name = "proc-macro-hack" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598" + +[[package]] +name = "proc-macro-nested" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" + +[[package]] +name = "proc-macro2" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175c513d55719db99da20232b06cda8bab6b83ec2d04e3283edf0213c37c1a29" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "regex" +version = "1.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", +] + +[[package]] +name = "regex-syntax" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" + +[[package]] +name = "route-recognizer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56770675ebc04927ded3e60633437841581c285dc6236109ea25fbf3beb7b59e" + +[[package]] +name = "router" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-process", + "blocking 0.6.1", + "config", + "futures-lite 1.0.0", + "mime", + "once_cell", + "regex", + "ructe", + "serde 1.0.115", + "serde_json", + "sled", + "tide", +] + +[[package]] +name = "rsass" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c78e9b85b8816881cad9aa1142eec337020cfd79c6983e338811f5c521a80463" +dependencies = [ + "bytecount", + "lazy_static", + "nom", + "num-rational", + "num-traits 0.2.12", + "rand", +] + +[[package]] +name = "ructe" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8ffc645837eab09b6cbb6772d18897c6309753254592e149b40ff7fb113c01" +dependencies = [ + "base64", + "bytecount", + "itertools", + "md5", + "mime", + "nom", + "rsass", +] + +[[package]] +name = "rust-ini" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" + +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "serde" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" + +[[package]] +name = "serde" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-hjson" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8" +dependencies = [ + "lazy_static", + "linked-hash-map 0.3.0", + "num-traits 0.1.43", + "regex", + "serde 0.8.23", +] + +[[package]] +name = "serde_derive" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" +dependencies = [ + "itoa", + "ryu", + "serde 1.0.115", +] + +[[package]] +name = "serde_qs" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f3acf84e23ab27c01cb5917551765c01c50b2000089db8fa47fe018a3260cf" +dependencies = [ + "data-encoding", + "error-chain", + "percent-encoding", + "serde 1.0.115", +] + +[[package]] +name = "serde_test" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" +dependencies = [ + "serde 0.8.23", +] + +[[package]] +name = "serde_urlencoded" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" +dependencies = [ + "dtoa", + "itoa", + "serde 1.0.115", + "url", +] + +[[package]] +name = "sha1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" + +[[package]] +name = "sha2" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1" +dependencies = [ + "block-buffer", + "cfg-if", + "cpuid-bool", + "digest", + "opaque-debug 0.3.0", +] + +[[package]] +name = "signal-hook" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604508c1418b99dfe1925ca9224829bb2a8a9a04dda655cc01fcad46f4ab05ed" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035" +dependencies = [ + "arc-swap", + "libc", +] + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] +name = "sled" +version = "0.34.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbf56c35b0c3f9bc208fab35e45c3bc03137d3c1a4a85bdf0b8db69aecffb45" +dependencies = [ + "crc32fast", + "crossbeam-epoch", + "crossbeam-utils", + "fs2", + "fxhash", + "libc", + "log", + "parking_lot", + "zstd", +] + +[[package]] +name = "smallvec" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" + +[[package]] +name = "socket2" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "winapi", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "standback" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33a71ea1ea5f8747d1af1979bfb7e65c3a025a70609f04ceb78425bc5adad8e6" +dependencies = [ + "version_check", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde 1.0.115", + "serde_derive", + "syn", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde 1.0.115", + "serde_derive", + "serde_json", + "sha1", + "syn", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + +[[package]] +name = "subtle" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502d53007c02d7605a05df1c1a73ee436952781653da5d0bf57ad608f66932c1" + +[[package]] +name = "syn" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "tide" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c4c4e35f5a89ed08cbb59b6e4e1d648e563d6f8daa804002f3557d11d3c8f9" +dependencies = [ + "async-h1", + "async-session", + "async-sse", + "async-std", + "async-trait", + "femme", + "futures-util", + "http-types", + "kv-log-macro", + "pin-project-lite", + "route-recognizer", + "serde 1.0.115", + "serde_json", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "time" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca7ec98a72285d12e0febb26f0847b12d54be24577618719df654c66cadab55d" +dependencies = [ + "const_fn", + "libc", + "standback", + "stdweb", + "time-macros", + "version_check", + "winapi", +] + +[[package]] +name = "time-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9b6e9f095bc105e183e3cd493d72579be3181ad4004fceb01adbe9eecab2d" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] + +[[package]] +name = "time-macros-impl" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn", +] + +[[package]] +name = "tinyvec" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117" + +[[package]] +name = "toml" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" +dependencies = [ + "serde 1.0.115", +] + +[[package]] +name = "typenum" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +dependencies = [ + "matches", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "universal-hash" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "url" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" +dependencies = [ + "idna", + "matches", + "percent-encoding", + "serde 1.0.115", +] + +[[package]] +name = "vec-arena" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb18268690309760d59ee1a9b21132c126ba384f374c59a94db4bc03adeb561" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasm-bindgen" +version = "0.2.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0563a9a4b071746dd5aedbc3a28c6fe9be4586fb3fbadb67c400d4f53c6b16c" +dependencies = [ + "cfg-if", + "serde 1.0.115", + "serde_json", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc71e4c5efa60fb9e74160e89b93353bc24059999c0ae0fb03affc39770310b0" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95f8d235a77f880bcef268d379810ea6c0af2eacfa90b1ad5af731776e0c4699" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97c57cefa5fa80e2ba15641578b44d36e7a64279bc5ed43c6dbaf329457a2ed2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93b162580e34310e5931c4b792560108b10fd14d64915d7fff8ff00180e70092" + +[[package]] +name = "web-sys" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dda38f4e5ca63eda02c059d243aa25b5f35ab98451e518c51612cd0f1bd19a47" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wepoll-sys-stjepang" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fd319e971980166b53e17b1026812ad66c6b54063be879eb182342b55284694" +dependencies = [ + "cc", +] + +[[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 = "yaml-rust" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d" +dependencies = [ + "linked-hash-map 0.5.3", +] + +[[package]] +name = "zstd" +version = "0.5.3+zstd.1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01b32eaf771efa709e8308605bbf9319bf485dc1503179ec0469b611937c0cd8" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "2.0.5+zstd.1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfb642e0d27f64729a639c52db457e0ae906e7bc6f5fe8f5c453230400f1055" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "1.4.17+zstd.1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89249644df056b522696b1bb9e7c18c87e8ffa3e2f0dc3b0155875d6498f01b" +dependencies = [ + "cc", + "glob", + "itertools", + "libc", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0dc97a3 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "router" +version = "0.1.0" +authors = ["asonix "] +edition = "2018" +build = "src/build.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0" +async-process = "0.1.3" +blocking = "0.6.1" +config = { version = "0.10.1", features = ["toml"] } +futures-lite = "1.0.0" +mime = "0.3" +once_cell = "1.4.1" +regex = "1.3.9" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +sled = { version = "0.34.3", features = ["compression"] } +tide = "0.13.0" + +[build-dependencies] +anyhow = "1.0" +ructe = { version = "0.12.0", features = ["sass", "mime03"] } diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..4a51d76 --- /dev/null +++ b/config.toml @@ -0,0 +1,8 @@ +[interface] +external = "eth[0-9]+" +internal = [ + "enp1s0" +] + +[network] +shared-internal = true diff --git a/scss/index.scss b/scss/index.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/build.rs b/src/build.rs new file mode 100644 index 0000000..3d6a781 --- /dev/null +++ b/src/build.rs @@ -0,0 +1,10 @@ +use ructe::Ructe; + +fn main() -> Result<(), anyhow::Error> { + let mut ructe = Ructe::from_env()?; + let mut statics = ructe.statics()?; + statics.add_sass_file("scss/index.scss")?; + ructe.compile_templates("templates")?; + + Ok(()) +} diff --git a/src/iptables.rs b/src/iptables.rs new file mode 100644 index 0000000..6098327 --- /dev/null +++ b/src/iptables.rs @@ -0,0 +1,302 @@ +use async_process::Command; +use std::{fmt, net::Ipv4Addr}; + +#[derive(Clone, Copy, Debug, serde::Deserialize, serde::Serialize)] +pub(crate) enum Proto { + Tcp, + Udp, +} + +impl Proto { + fn as_str(&self) -> &'static str { + match self { + Proto::Tcp => "tcp", + Proto::Udp => "udp", + } + } +} + +impl fmt::Display for Proto { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Proto::Tcp => write!(f, "TCP"), + Proto::Udp => write!(f, "UDP"), + } + } +} + +pub(crate) async fn input_accept( + external_interface: &str, + external_ip: Ipv4Addr, + external_port: u16, + external_mask: u8, +) -> Result<(), anyhow::Error> { + input( + external_interface, + external_ip, + external_port, + external_mask, + move |cmd| cmd.arg("-I"), + ) + .await +} + +pub(crate) async fn delete_input_accept( + external_interface: &str, + external_ip: Ipv4Addr, + external_port: u16, + external_mask: u8, +) -> Result<(), anyhow::Error> { + input( + external_interface, + external_ip, + external_port, + external_mask, + move |cmd| cmd.arg("-D"), + ) + .await +} + +async fn input( + external_interface: &str, + external_ip: Ipv4Addr, + external_port: u16, + external_mask: u8, + func: impl Fn(&mut Command) -> &mut Command, +) -> Result<(), anyhow::Error> { + iptables(move |cmd| { + func(cmd).args(&[ + "INPUT", + "-d", + &format!("{}/{}", external_ip, external_mask), + "-i", + external_interface, + "-p", + "tcp", + "-m", + "conntrack", + "--ctstate", + "NEW,RELATED,ESTABLISHED", + "-m", + "tcp", + "--dport", + &external_port.to_string(), + "-j", + "ACCEPT", + ]) + }) + .await +} + +pub(crate) async fn forward_accept( + external_interface: &str, + internal_interface: &str, + proto: Proto, + external_port: u16, +) -> Result<(), anyhow::Error> { + forward( + external_interface, + internal_interface, + proto, + external_port, + move |cmd| cmd.arg("-I"), + ) + .await +} + +pub(crate) async fn delete_forward_accept( + external_interface: &str, + internal_interface: &str, + proto: Proto, + external_port: u16, +) -> Result<(), anyhow::Error> { + forward( + external_interface, + internal_interface, + proto, + external_port, + move |cmd| cmd.arg("-I"), + ) + .await +} + +async fn forward( + external_interface: &str, + internal_interface: &str, + proto: Proto, + external_port: u16, + func: impl Fn(&mut Command) -> &mut Command, +) -> Result<(), anyhow::Error> { + iptables(move |cmd| { + func(cmd).args(&[ + "FORWARD", + "-i", + external_interface, + "-o", + internal_interface, + "-p", + proto.as_str(), + "--dport", + &external_port.to_string(), + "-m", + "conntrack", + "--ctstate", + "NEW,ESTABLISHED,RELATED", + "-j", + "ACCEPT", + ]) + }) + .await +} + +pub(crate) async fn forward_postrouting( + external_ip: Ipv4Addr, + external_port: u16, + destination_ip: Ipv4Addr, +) -> Result<(), anyhow::Error> { + forward_postrouting_snat(external_ip, external_port, destination_ip, |cmd| { + cmd.arg("-I") + }) + .await +} + +pub(crate) async fn delete_forward_postrouting( + external_ip: Ipv4Addr, + external_port: u16, + destination_ip: Ipv4Addr, +) -> Result<(), anyhow::Error> { + forward_postrouting_snat(external_ip, external_port, destination_ip, |cmd| { + cmd.arg("-D") + }) + .await +} + +async fn forward_postrouting_snat( + external_ip: Ipv4Addr, + external_port: u16, + destination_ip: Ipv4Addr, + func: impl Fn(&mut Command) -> &mut Command, +) -> Result<(), anyhow::Error> { + iptables_nat(move |cmd| { + func(cmd).args(&[ + "POSTROUTING", + "-d", + &destination_ip.to_string(), + "-p", + "tcp", + "-m", + "tcp", + "--dport", + &external_port.to_string(), + "-m", + "conntrack", + "--ctstate", + "NEW,RELATED,ESTABLISHED", + "-j", + "SNAT", + "--to-source", + &external_ip.to_string(), + ]) + }) + .await +} + +pub(crate) async fn forward_prerouting( + proto: Proto, + external_ip: Ipv4Addr, + external_mask: u8, + external_port: u16, + destination_ip: Ipv4Addr, + destination_port: u16, +) -> Result<(), anyhow::Error> { + forward_prerouting_dnat( + proto, + external_ip, + external_mask, + external_port, + destination_ip, + destination_port, + |cmd| cmd.arg("-I"), + ) + .await +} + +pub(crate) async fn delete_forward_prerouting( + proto: Proto, + external_ip: Ipv4Addr, + external_mask: u8, + external_port: u16, + destination_ip: Ipv4Addr, + destination_port: u16, +) -> Result<(), anyhow::Error> { + forward_prerouting_dnat( + proto, + external_ip, + external_mask, + external_port, + destination_ip, + destination_port, + |cmd| cmd.arg("-D"), + ) + .await +} + +async fn forward_prerouting_dnat( + proto: Proto, + external_ip: Ipv4Addr, + external_mask: u8, + external_port: u16, + destination_ip: Ipv4Addr, + destination_port: u16, + func: impl Fn(&mut Command) -> &mut Command, +) -> Result<(), anyhow::Error> { + iptables_nat(move |cmd| { + func(cmd).args(&[ + "PREROUTING", + "-p", + proto.as_str(), + "-d", + &format!("{}/{}", external_ip, external_mask), + "--dport", + &external_port.to_string(), + "-m", + "conntrack", + "--ctstate", + "NEW,ESTABLISHED,RELATED", + "-j", + "DNAT", + "--to", + format!("{}:{}", destination_ip, destination_port).as_str(), + ]) + }) + .await +} + +async fn iptables_nat(func: F) -> Result<(), anyhow::Error> +where + F: Fn(&mut Command) -> &mut Command, +{ + iptables(move |cmd| func(cmd.args(&["-t", "nat"]))).await +} + +async fn iptables(func: F) -> Result<(), anyhow::Error> +where + F: Fn(&mut Command) -> &mut Command, +{ + let mut command = Command::new("iptables"); + + func(&mut command); + + let mut child = command.spawn()?; + + let status = child.status().await?; + + if !status.success() { + return Err(anyhow::Error::msg(format!( + "Command failed with status {}", + status + ))); + } + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..87dd5dd --- /dev/null +++ b/src/main.rs @@ -0,0 +1,84 @@ +use blocking::unblock; +use futures_lite::*; +use once_cell::sync::Lazy; +use sled::Db; + +include!(concat!(env!("OUT_DIR"), "/templates.rs")); + +mod iptables; +mod rules; +mod startup; + +use self::{rules::Rule, startup::Interfaces}; + +static INTERFACES: Lazy = Lazy::new(|| { + let interfaces = Interfaces::init_blocking().unwrap(); + interfaces.reset_blocking().unwrap(); + interfaces +}); + +static DB: Lazy = Lazy::new(|| sled::open("router-db-0-34-3").unwrap()); + +async fn rules_page(_: tide::Request<()>) -> tide::Result { + let mut html = Vec::new(); + + let rules = unblock(move || rules::read(&DB)).await?; + + templates::rules(&mut html, &rules)?; + + Ok(tide::Response::builder(200) + .body(html) + .content_type( + "text/html;charset=utf-8" + .parse::() + .unwrap(), + ) + .build()) +} + +async fn save_rule(mut req: tide::Request<()>) -> tide::Result { + let rule: Rule = req.body_form().await?; + + rules::save(&DB, &rule)?; + rules::apply(&INTERFACES, rule).await?; + + Ok(to_rules_page()) +} + +async fn delete_rule(req: tide::Request<()>) -> tide::Result { + let id = req.param("id")?; + let rule = rules::delete(&DB, id)?; + rules::unset(&INTERFACES, rule).await?; + + Ok(to_rules_page()) +} + +fn to_rules_page() -> tide::Response { + tide::Response::builder(301) + .header("Location", "/rules") + .build() +} + +fn main() -> Result<(), anyhow::Error> { + future::block_on(async { + println!("Hello, world!"); + + rules::apply_all(&DB, &INTERFACES).await?; + + let mut app = tide::new(); + app.at("/rules").get(rules_page).post(save_rule); + app.at("/rules/:id").delete(delete_rule); + + let listeners: Vec = INTERFACES + .internal + .iter() + .map(|info| format!("{}:8080", info.ip)) + .collect(); + + app.listen(listeners).await?; + + Ok(()) as Result<(), anyhow::Error> + })?; + + Ok(()) +} diff --git a/src/rules.rs b/src/rules.rs new file mode 100644 index 0000000..32b332e --- /dev/null +++ b/src/rules.rs @@ -0,0 +1,148 @@ +use crate::{ + iptables::{self, Proto}, + startup::Interfaces, +}; +use sled::Db; +use std::net::Ipv4Addr; + +#[derive(serde::Deserialize, serde::Serialize)] +pub struct Rule { + pub(crate) proto: Proto, + pub(crate) port: u16, + pub(crate) kind: RuleKind, +} + +impl Rule { + pub(crate) fn as_forward(&self) -> Option<(Ipv4Addr, u16)> { + match &self.kind { + RuleKind::Forward { dest_ip, dest_port } => Some((*dest_ip, *dest_port)), + _ => None, + } + } +} + +#[derive(serde::Deserialize, serde::Serialize)] +#[serde(tag = "type")] +pub(crate) enum RuleKind { + Accept, + Forward { dest_ip: Ipv4Addr, dest_port: u16 }, +} + +pub(crate) async fn apply_all(db: &Db, interfaces: &Interfaces) -> Result<(), anyhow::Error> { + for (_, rule) in read(db)? { + apply(interfaces, rule).await?; + } + + Ok(()) +} + +pub(crate) fn read(db: &Db) -> Result, anyhow::Error> { + db.iter() + .map(|res| { + let (id, rule) = res?; + + let id = String::from_utf8_lossy(&id).to_string(); + let rule: Rule = serde_json::from_slice(&rule)?; + + Ok((id, rule)) as Result<(String, Rule), anyhow::Error> + }) + .collect::, anyhow::Error>>() +} + +pub(crate) fn delete(db: &Db, rule_id: String) -> Result { + let rule = db + .remove(rule_id.as_bytes())? + .ok_or(anyhow::anyhow!("No rule with id {}", rule_id))?; + + let rule: Rule = serde_json::from_slice(&rule)?; + + Ok(rule) +} + +pub(crate) async fn unset(interfaces: &Interfaces, rule: Rule) -> Result<(), anyhow::Error> { + match rule.kind { + RuleKind::Accept => { + iptables::delete_input_accept( + &interfaces.external.interface, + interfaces.external.ip, + rule.port, + interfaces.external.mask, + ) + .await?; + } + RuleKind::Forward { dest_ip, dest_port } => { + for info in &interfaces.internal { + iptables::delete_forward_accept( + &interfaces.external.interface, + &info.interface, + rule.proto, + rule.port, + ) + .await?; + } + iptables::delete_forward_prerouting( + rule.proto, + interfaces.external.ip, + interfaces.external.mask, + rule.port, + dest_ip, + dest_port, + ) + .await?; + iptables::delete_forward_postrouting(interfaces.external.ip, rule.port, dest_ip) + .await?; + } + } + + Ok(()) +} + +pub(crate) fn save(db: &Db, rule: &Rule) -> Result<(), anyhow::Error> { + let s = serde_json::to_string(rule)?; + let id = db.generate_id()?; + + db.insert(rule_id(id).as_bytes(), s.as_bytes())?; + + Ok(()) +} + +pub(crate) async fn apply(interfaces: &Interfaces, rule: Rule) -> Result<(), anyhow::Error> { + match rule.kind { + RuleKind::Accept => { + iptables::input_accept( + &interfaces.external.interface, + interfaces.external.ip, + rule.port, + interfaces.external.mask, + ) + .await?; + } + RuleKind::Forward { dest_ip, dest_port } => { + for info in &interfaces.internal { + iptables::forward_accept( + &interfaces.external.interface, + &info.interface, + rule.proto, + rule.port, + ) + .await?; + } + iptables::forward_prerouting( + rule.proto, + interfaces.external.ip, + interfaces.external.mask, + rule.port, + dest_ip, + dest_port, + ) + .await?; + iptables::forward_postrouting(interfaces.external.ip, rule.port, dest_ip).await?; + } + } + + Ok(()) +} + +fn rule_id(id: u64) -> String { + format!("rule-{}", id) +} diff --git a/src/startup/mod.rs b/src/startup/mod.rs new file mode 100644 index 0000000..fb908af --- /dev/null +++ b/src/startup/mod.rs @@ -0,0 +1,185 @@ +use anyhow::anyhow; +use regex::Regex; +use std::{ + io::Write, + net::Ipv4Addr, + process::{Command, Stdio}, +}; + +mod preload; + +#[derive(serde::Deserialize)] +struct Config { + interface: InterfaceConfig, + network: NetworkConfig, +} + +#[derive(serde::Deserialize)] +struct InterfaceConfig { + external: String, + internal: Vec, +} + +#[derive(serde::Deserialize)] +#[serde(rename_all = "kebab-case")] +struct NetworkConfig { + shared_internal: bool, +} + +pub(crate) struct Interfaces { + pub(crate) external: InterfaceInfo, + pub(crate) internal: Vec, + shared_internal: bool, +} + +pub(crate) struct InterfaceInfo { + pub(crate) interface: String, + pub(crate) ip: Ipv4Addr, + pub(crate) mask: u8, +} + +impl Config { + fn read() -> Result { + let mut config = config::Config::new(); + config.merge(config::File::with_name("config.toml"))?; + + Ok(config.try_into()?) + } +} + +impl Interfaces { + pub(crate) fn init_blocking() -> Result { + let config = Config::read()?; + + let output = Command::new("ip").arg("addr").output()?; + let output = String::from_utf8_lossy(&output.stdout); + + let external = parse_interface_info(&output, &config.interface.external)? + .next() + .ok_or(anyhow!( + "Failed to parse IP for interface {}", + config.interface.external, + ))?; + + let mut internal = Vec::new(); + + for iface in &config.interface.internal { + internal.extend(parse_interface_info(&output, &iface)?); + } + + if internal.len() == 0 { + return Err(anyhow!( + "No internal interfaces found for {:?}", + config.interface.internal + )); + } + + Ok(Interfaces { + external, + internal, + shared_internal: config.network.shared_internal, + }) + } + + pub(crate) fn reset_blocking(&self) -> Result<(), anyhow::Error> { + let firewall_rules = self::preload::firewall_rules(self); + + println!("LOADING RULES"); + println!("{}", firewall_rules); + + let mut child = Command::new("iptables-restore") + .stdin(Stdio::piped()) + .spawn()?; + + let stdin = child + .stdin + .as_mut() + .expect("Failed to open STDIN (shouldn't happen)"); + stdin.write_all(firewall_rules.as_bytes())?; + + child.wait()?; + + Ok(()) + } +} + +fn parse_interface_info<'a>( + output: &'a str, + interface: &str, +) -> Result + 'a, anyhow::Error> { + let iface_regx = Regex::new(interface)?; + let ip_regex = Regex::new(r"([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/([0-9]+)")?; + + let iter = output.split('\n').filter_map(move |line| { + let iface_capture = iface_regx.captures_iter(line).next()?; + let iface_match = iface_capture.get(0)?; + + let ip_capture = ip_regex.captures_iter(line).next()?; + let ip_match = ip_capture.get(1)?; + let mask_match = ip_capture.get(2)?; + + let ip = ip_match.as_str().parse().ok()?; + let mask = mask_match.as_str().parse().ok()?; + + Some(InterfaceInfo { + interface: iface_match.as_str().to_owned(), + mask, + ip, + }) + }); + + Ok(iter) +} + +#[cfg(test)] +mod tests { + use super::parse_interface_info; + + const OUTPUT: &'static str = r#"1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + inet 127.0.0.1/8 scope host lo + valid_lft forever preferred_lft forever + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever +2: enp1s0: mtu 1500 qdisc mq state UP group default qlen 1000 + link/ether 24:4b:fe:37:ad:b1 brd ff:ff:ff:ff:ff:ff + inet 192.168.6.1/24 brd 192.168.5.255 scope global enp1s0 + valid_lft forever preferred_lft forever + inet6 fe80::264b:feff:fe37:adb1/64 scope link + valid_lft forever preferred_lft forever +3: eth1: mtu 1500 qdisc mq state UP group default qlen 1000 + link/ether ca:b8:a7:51:07:3d brd ff:ff:ff:ff:ff:ff + inet 136.49.5.58/20 brd 136.49.15.255 scope global dynamic eth1 + valid_lft 85973sec preferred_lft 85973sec + inet6 fe80::c8b8:a7ff:fe51:73d/64 scope link + valid_lft forever preferred_lft forever +4: wg0: mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000 + link/none + inet 192.168.5.0/24 scope global wg0 + valid_lft forever preferred_lft forever +"#; + + #[test] + fn parses_external_interface() { + let info = parse_interface_info(OUTPUT, "eth[0-9]+") + .unwrap() + .next() + .unwrap(); + + assert_eq!(info.interface, "eth1"); + assert_eq!(info.ip.to_string(), "136.49.5.58"); + assert_eq!(info.mask, 20); + } + + #[test] + fn parses_internal_interface() { + let info = parse_interface_info(OUTPUT, "enp1s0") + .unwrap() + .next() + .unwrap(); + + assert_eq!(info.interface, "enp1s0"); + assert_eq!(info.ip.to_string(), "192.168.6.1"); + assert_eq!(info.mask, 24); + } +} diff --git a/src/startup/preload.rs b/src/startup/preload.rs new file mode 100644 index 0000000..f5e78e0 --- /dev/null +++ b/src/startup/preload.rs @@ -0,0 +1,259 @@ +use crate::startup::Interfaces; + +static UNIVERSE: &'static str = "0.0.0.0/0"; + +pub(crate) fn firewall_rules(interfaces: &Interfaces) -> String { + filter(interfaces) + "\n" + &nat(interfaces) +} + +// FILTER table rules +fn filter(interfaces: &Interfaces) -> String { + let mut filter = String::from( + r#"*filter +:INPUT DROP [0:0] +:FORWARD DROP [0:0] +:OUTPUT DROP [0:0] + +"#, + ); + + // INPUT: Incoming traffic from various interfaces + + // Accept everything on loopback + filter += &format!( + "-A INPUT -i lo -s {universe} -d {universe} -j ACCEPT\n", + universe = UNIVERSE + ); + + // Allow internal machines to connect to anything + for iface in &interfaces.internal { + filter += &format!( + "-A INPUT -i {intif} -s {intip}/{intmask} -d {universe} -j ACCEPT\n", + intif = iface.interface, + intip = iface.ip, + intmask = iface.mask, + universe = UNIVERSE + ); + } + + // Disallow IP spoofing, internal IPs should only come from the internal network + // If an internal IP is seen by the external interface, it's BAD!!!! + for iface in &interfaces.internal { + filter += &format!( + "-A INPUT -i {extif} -s {intip}/{intmask} -d {universe} -j REJECT\n", + extif = interfaces.external.interface, + intip = iface.ip, + intmask = iface.mask, + universe = UNIVERSE, + ); + } + + // Allow ICMP traffic on external interface + filter += &format!( + "-A INPUT -i {extif} -p ICMP -s {universe} -d {extip}/{extmask} -j ACCEPT\n", + extif = interfaces.external.interface, + universe = UNIVERSE, + extip = interfaces.external.ip, + extmask = interfaces.external.mask, + ); + + // Don't prevent existing connections for continuing + filter += &format!( + "-A INPUT -i {extif} -s {universe} -d {extip}/{extmask} -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\n", + extif = interfaces.external.interface, + universe = UNIVERSE, + extip = interfaces.external.ip, + extmask = interfaces.external.mask, + ); + + // Allow DHCP traffic + for iface in &interfaces.internal { + filter += &format!( + "-A INPUT -i {intif} -p tcp --sport 68 --dport 67 -j ACCEPT\n", + intif = iface.interface, + ); + + filter += &format!( + "-A INPUT -i {intif} -p udp --sport 68 --dport 67 -j ACCEPT\n", + intif = iface.interface, + ); + } + + filter += &format!( + "-A INPUT -s {universe} -d {universe} -j REJECT\n", + universe = UNIVERSE + ); + + // OUTPUT: Outgoing traffic from vairous interfaces + + // netfilter bug workaround + filter += "-A OUTPUT -m conntrack -p icmp --ctstate INVALID -j DROP\n"; + + // Accept everything on loopback + filter += &format!( + "-A OUTPUT -o lo -s {universe} -d {universe} -j ACCEPT\n", + universe = UNIVERSE, + ); + + if interfaces.shared_internal { + for iface in &interfaces.internal { + // jface (jeans iface) + for jface in &interfaces.internal { + // Allow internal traffic across all internal interfaces + filter += &format!( + "-A OUTPUT -o {intif} -s {extip}/{extmask} -d {jntip}/{jntmask} -j ACCEPT\n", + intif = iface.interface, + extip = interfaces.external.ip, + extmask = interfaces.external.mask, + jntip = jface.ip, // jeans IP + jntmask = jface.mask, // jeans mask + ); + + // Allow internal traffic from self to internal networks + filter += &format!( + "-A OUTPUT -o {intif} -s {intip}/32 -d {jntip}/{jntmask} -j ACCEPT\n", + intif = iface.interface, + intip = iface.ip, + jntip = jface.ip, // jeans IP + jntmask = jface.mask, // jeans mask + ); + } + } + } else { + for iface in &interfaces.internal { + // Allow internal traffic only on network associated with interface + filter += &format!( + "-A OUTPUT -o {intif} -s {extip}/{extmask} -d {intip}/{intmask} -j ACCEPT\n", + intif = iface.interface, + extip = interfaces.external.ip, + extmask = interfaces.external.mask, + intip = iface.ip, + intmask = iface.mask, + ); + + // Allow traffic from self to networks associated with interface + filter += &format!( + "-A OUTPUT -o {intif} -s {intip}/32 -d {intip}/{intmask} -j ACCEPT\n", + intif = iface.interface, + intip = iface.ip, + intmask = iface.mask, + ); + } + } + + for iface in &interfaces.internal { + // Deny traffic to internal networks on external interface + filter += &format!( + "-A OUTPUT -o {extif} -s {universe} -d {intip}/{intmask} -j REJECT\n", + extif = interfaces.external.interface, + universe = UNIVERSE, + intip = iface.ip, + intmask = iface.mask, + ); + } + + // Allow traffic out from external interface to anywhere + filter += &format!( + "-A OUTPUT -o {extif} -s {extip}/{extmask} -d {universe} -j ACCEPT\n", + extif = interfaces.external.interface, + extip = interfaces.external.ip, + extmask = interfaces.external.mask, + universe = UNIVERSE, + ); + + for iface in &interfaces.internal { + // Allow DHCP traffic out from internal interfaces + filter += &format!( + "-A OUTPUT -o {intif} -p tcp -s {intip} --sport 67 -d 255.255.255.255 --dport 68 -j ACCEPT\n", + intif = iface.interface, + intip = iface.ip, + ); + + filter += &format!( + "-A OUTPUT -o {intif} -p udp -s {intip} --sport 67 -d 255.255.255.255 --dport 68 -j ACCEPT\n", + intif = iface.interface, + intip = iface.ip, + ); + } + + // Reject traffic we don't care about + filter += &format!( + "-A OUTPUT -s {universe} -d {universe} -j REJECT\n", + universe = UNIVERSE + ); + + // FORWARD: Forwarding traffic across interfaces + + // Accept TCP packets + for iface in &interfaces.internal { + filter += &format!( + "-A FORWARD -i {extif} -o {intif} -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\n", + extif = interfaces.external.interface, + intif = iface.interface, + ); + } + + if interfaces.shared_internal { + for iface in &interfaces.internal { + // jface (jeans interface) + for jface in &interfaces.internal { + // Allow packets across internal interfaces + filter += &format!( + "-A FORWARD -i {intif} -o {jntif} -j ACCEPT\n", + intif = iface.interface, + jntif = jface.interface, // jntif (jeans intif) + ); + } + } + } else { + for iface in &interfaces.internal { + // Allow packets across internal interface + filter += &format!( + "-A FORWARD -i {intif} -o {intif} -j ACCEPT\n", + intif = iface.interface, + ); + } + } + + // Forward packets to the internet + for iface in &interfaces.internal { + filter += &format!( + "-A FORWARD -i {intif} -o {extif} -j ACCEPT\n", + intif = iface.interface, + extif = interfaces.external.interface, + ); + } + + filter += "-A FORWARD -j REJECT\n"; + filter += "COMMIT\n"; + + filter +} + +// NAT Table rules +fn nat(interfaces: &Interfaces) -> String { + let mut nat = String::from( + r#"*nat +:PREROUTING ACCEPT [0:0] +:POSTROUTING ACCEPT [0:0] +:OUTPUT ACCEPT [0:0] + +"#, + ); + + nat += &format!( + "-A POSTROUTING -o {extif} -j MASQUERADE\n", + extif = interfaces.external.interface + ); + + nat += "COMMIT\n"; + + nat +} + +// TODO: SSH +// # Internal interface, SSH traffic accepted on port 3128 +// -A INPUT -i $INTIF -p tcp --dport 3128 -j ACCEPT +// +// # External interface, SSH traffic allowed on port 3128 +// -A INPUT -i $EXTIF -m conntrack -p tcp -s $UNIVERSE -d $EXTIP --dport 3128 -j ACCEPT diff --git a/templates/rules.rs.html b/templates/rules.rs.html new file mode 100644 index 0000000..08be362 --- /dev/null +++ b/templates/rules.rs.html @@ -0,0 +1,61 @@ +@use crate::rules::Rule; + +@(rules: &[(String, Rule)]) + + + + + + + Rules + + + + + + + + + + + + @for (id, rule) in rules { + @if let Some((dest_ip, dest_port)) = rule.as_forward() { + + + + + + } else { + + + + + + } + + } + +
KindProtocolPortDestination
Forward@rule.proto@rule.port@dest_ip@dest_portAccept@rule.proto@rule.portDelete
+
+ + + + + + +
+ +