diff --git a/Cargo.lock b/Cargo.lock index 8be3f76a..39d9debc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,9 +69,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.12" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b09b5178381e0874812a9b157f7fe84982617e48f71f4e3235482775e5b540" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -141,9 +141,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "arc-swap" @@ -171,20 +171,20 @@ checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.57", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -233,9 +233,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "blake3" @@ -280,14 +280,14 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.57", ] [[package]] name = "bumpalo" -version = "3.15.0" +version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "byte_string" @@ -339,10 +339,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" dependencies = [ + "jobserver", "libc", ] @@ -396,14 +397,14 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.34" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -498,10 +499,28 @@ dependencies = [ ] [[package]] -name = "crossbeam-channel" -version = "0.5.11" +name = "crc32fast" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] @@ -579,7 +598,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.57", ] [[package]] @@ -680,6 +699,12 @@ dependencies = [ "signature", ] +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + [[package]] name = "elliptic-curve" version = "0.13.8" @@ -716,7 +741,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.57", ] [[package]] @@ -778,9 +803,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "ff" @@ -800,10 +825,16 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.4.1", "windows-sys 0.52.0", ] +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "fnv" version = "1.0.7" @@ -834,6 +865,16 @@ 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 = "fsevent-sys" version = "4.1.0" @@ -899,7 +940,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.57", ] [[package]] @@ -932,6 +973,15 @@ dependencies = [ "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.7" @@ -958,9 +1008,9 @@ dependencies = [ [[package]] name = "ghash" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ "opaque-debug", "polyval", @@ -985,16 +1035,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", - "http 0.2.11", + "http 0.2.12", "indexmap", "slab", "tokio", @@ -1004,16 +1054,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31d030e59af851932b72ceebadf4a2b5986dba4c3b99dd2493f8273a0f151943" +checksum = "51ee2dd2e4f378392eeff5d51618cd9a63166a2513846bbc55f21cfacd9199d4" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", - "http 1.0.0", + "http 1.1.0", "indexmap", "slab", "tokio", @@ -1030,7 +1080,7 @@ dependencies = [ "bytes", "fastrand 1.9.0", "futures-util", - "http 0.2.11", + "http 0.2.12", "tokio", "tracing", ] @@ -1082,9 +1132,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hickory-proto" @@ -1100,10 +1150,10 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "h2 0.3.24", + "h2 0.3.25", "h3", "h3-quinn", - "http 0.2.11", + "http 0.2.12", "idna 0.4.0", "ipnet", "native-tls", @@ -1136,7 +1186,7 @@ dependencies = [ "ipconfig", "lru-cache", "once_cell", - "parking_lot", + "parking_lot 0.12.1", "rand", "resolv-conf", "rustls 0.21.10", @@ -1169,6 +1219,15 @@ dependencies = [ "digest", ] +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "hostname" version = "0.3.1" @@ -1182,9 +1241,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -1193,9 +1252,9 @@ dependencies = [ [[package]] name = "http" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", @@ -1209,7 +1268,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", - "http 1.0.0", + "http 1.1.0", ] [[package]] @@ -1220,7 +1279,7 @@ checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" dependencies = [ "bytes", "futures-core", - "http 1.0.0", + "http 1.1.0", "http-body", "pin-project-lite", ] @@ -1252,8 +1311,8 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.2", - "http 1.0.0", + "h2 0.4.3", + "http 1.1.0", "http-body", "httparse", "httpdate", @@ -1271,10 +1330,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" dependencies = [ "futures-util", - "http 1.0.0", + "http 1.1.0", "hyper", "hyper-util", - "rustls 0.22.2", + "rustls 0.22.3", "rustls-pki-types", "tokio", "tokio-rustls 0.25.0", @@ -1306,7 +1365,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.0.0", + "http 1.1.0", "http-body", "hyper", "pin-project-lite", @@ -1362,9 +1421,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.3" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", @@ -1442,10 +1501,19 @@ dependencies = [ ] [[package]] -name = "itoa" -version = "1.0.10" +name = "itertools" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jemalloc-sys" @@ -1468,10 +1536,19 @@ dependencies = [ ] [[package]] -name = "js-sys" -version = "0.3.68" +name = "jobserver" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -1521,12 +1598,12 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libloading" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-targets 0.52.4", ] [[package]] @@ -1545,9 +1622,9 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", - "redox_syscall", + "redox_syscall 0.4.1", ] [[package]] @@ -1603,7 +1680,7 @@ dependencies = [ "log", "log-mdc", "once_cell", - "parking_lot", + "parking_lot 0.12.1", "rand", "serde", "serde-value", @@ -1663,9 +1740,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "mimalloc" @@ -1693,9 +1770,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", @@ -1703,6 +1780,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + [[package]] name = "native-tls" version = "0.2.11" @@ -1727,7 +1810,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "cfg-if", "cfg_aliases", "libc", @@ -1739,7 +1822,7 @@ version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "crossbeam-channel", "filetime", "fsevent-sys", @@ -1813,17 +1896,17 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.63" +version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "cfg-if", "foreign-types", "libc", @@ -1840,7 +1923,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.57", ] [[package]] @@ -1860,9 +1943,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.99" +version = "0.9.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" dependencies = [ "cc", "libc", @@ -1913,6 +1996,17 @@ dependencies = [ "primeorder", ] +[[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.1" @@ -1920,7 +2014,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.9", +] + +[[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]] @@ -1931,7 +2039,7 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.4.1", "smallvec", "windows-targets 0.48.5", ] @@ -1944,9 +2052,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.7" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546" +checksum = "56f8023d0fb78c8e03784ea1c7f3fa36e68a723138990b8d5a47d916b651e7a8" dependencies = [ "memchr", "thiserror", @@ -1955,9 +2063,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.7" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809" +checksum = "b0d24f72393fd16ab6ac5738bc33cdb6a9aa73f8b902e8fe29cf4e67d7dd1026" dependencies = [ "pest", "pest_generator", @@ -1965,28 +2073,38 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.7" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e" +checksum = "fdc17e2a6c7d0a492f0158d7a4bd66cc17280308bbaff78d5bef566dca35ab80" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.57", ] [[package]] name = "pest_meta" -version = "2.7.7" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a" +checksum = "934cd7631c050f4674352a6e835d5f6711ffbfb9345c2fc0107155ac495ae293" dependencies = [ "once_cell", "pest", "sha2", ] +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap", +] + [[package]] name = "pin-project" version = "1.1.5" @@ -2004,14 +2122,14 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.57", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -2048,9 +2166,9 @@ dependencies = [ [[package]] name = "polyval" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", "cpufeatures", @@ -2070,6 +2188,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + [[package]] name = "primeorder" version = "0.13.6" @@ -2105,13 +2233,67 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +dependencies = [ + "bytes", + "heck", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 1.0.109", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost", +] + [[package]] name = "qrcode" version = "0.14.0" @@ -2210,6 +2392,15 @@ dependencies = [ "getrandom", ] +[[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.4.1" @@ -2232,14 +2423,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.5", - "regex-syntax 0.8.2", + "regex-automata 0.4.6", + "regex-syntax 0.8.3", ] [[package]] @@ -2253,13 +2444,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -2270,9 +2461,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "reqwest" @@ -2286,8 +2477,8 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.4.2", - "http 1.0.0", + "h2 0.4.3", + "http 1.1.0", "http-body", "http-body-util", "hyper", @@ -2302,7 +2493,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.22.2", + "rustls 0.22.3", "rustls-native-certs 0.7.0", "rustls-pemfile 1.0.4", "rustls-pki-types", @@ -2437,11 +2628,11 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", @@ -2462,9 +2653,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +checksum = "99008d7ad0bbbea527ec27bddbc0e432c5b87d8175178cee68d2eec9c4a1813c" dependencies = [ "log", "ring 0.17.8", @@ -2493,7 +2684,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" dependencies = [ "openssl-probe", - "rustls-pemfile 2.1.0", + "rustls-pemfile 2.1.1", "rustls-pki-types", "schannel", "security-framework", @@ -2510,9 +2701,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c333bb734fcdedcea57de1602543590f545f127dc8b533324318fd492c5c70b" +checksum = "f48172685e6ff52a556baa527774f61fcaa884f59daf3375c62a3f1cd2549dab" dependencies = [ "base64 0.21.7", "rustls-pki-types", @@ -2520,9 +2711,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.3.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048a63e5b3ac996d78d402940b5fa47973d2d080c6c6fffa1d0f19c4445310b7" +checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247" [[package]] name = "rustls-webpki" @@ -2547,9 +2738,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" @@ -2600,9 +2791,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.2" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -2613,9 +2804,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" dependencies = [ "core-foundation-sys", "libc", @@ -2633,9 +2824,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -2652,20 +2843,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.57", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "itoa", "ryu", @@ -2686,9 +2877,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.31" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ "indexmap", "itoa", @@ -2853,11 +3044,14 @@ dependencies = [ "nix", "once_cell", "pin-project", + "prost", + "prost-build", "rand", "regex", "rustls-native-certs 0.7.0", "serde", "shadowsocks", + "sled", "smoltcp", "socket2", "spin 0.9.8", @@ -2899,9 +3093,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54ac45299ccbd390721be55b412d41931911f654fa99e2cb8bfb57184b2061fe" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" @@ -2912,6 +3106,23 @@ dependencies = [ "autocfg", ] +[[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", + "zstd", +] + [[package]] name = "sm4" version = "0.5.1" @@ -2923,9 +3134,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smoltcp" @@ -3026,9 +3237,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.49" +version = "2.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496" +checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" dependencies = [ "proc-macro2", "quote", @@ -3085,12 +3296,12 @@ checksum = "3b7ad73e635dd232c2c2106d59269f59a61de421cc6b95252d2d932094ff1f40" [[package]] name = "tempfile" -version = "3.10.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "fastrand 2.0.1", + "fastrand 2.0.2", "rustix", "windows-sys 0.52.0", ] @@ -3122,7 +3333,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.57", ] [[package]] @@ -3137,9 +3348,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -3195,16 +3406,16 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", "libc", "mio", "num_cpus", - "parking_lot", + "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", "socket2", @@ -3220,7 +3431,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.57", ] [[package]] @@ -3249,7 +3460,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" dependencies = [ - "rustls 0.22.2", + "rustls 0.22.3", "rustls-pki-types", "tokio", ] @@ -3333,7 +3544,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.57", ] [[package]] @@ -3435,9 +3646,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -3463,9 +3674,9 @@ dependencies = [ [[package]] name = "unsafe-libyaml" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "untrusted" @@ -3517,9 +3728,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -3542,9 +3753,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3552,24 +3763,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.57", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -3579,9 +3790,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3589,28 +3800,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.49", + "syn 2.0.57", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -3631,6 +3842,18 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + [[package]] name = "widestring" version = "1.0.2" @@ -3693,7 +3916,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -3731,7 +3954,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -3766,17 +3989,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -3793,9 +4016,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -3811,9 +4034,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -3829,9 +4052,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -3847,9 +4070,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -3865,9 +4088,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -3883,9 +4106,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -3901,9 +4124,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "winreg" @@ -3939,3 +4162,32 @@ name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + +[[package]] +name = "zstd" +version = "0.9.2+zstd.1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2390ea1bf6c038c39674f22d95f0564725fc06034a47129179810b2fc58caa54" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "4.1.3+zstd.1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e99d81b99fb3c2c2c794e3fe56c305c63d5173a16a46b5850b07c935ffc7db79" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "1.6.2+zstd.1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2daf2f248d9ea44454bfcb2516534e8b8ad2fc91bf818a1885495fc42bc8ac9f" +dependencies = [ + "cc", + "libc", +] diff --git a/Cargo.toml b/Cargo.toml index b146729b..da61f147 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -123,6 +123,8 @@ local-tunnel = ["local", "shadowsocks-service/local-tunnel"] local-socks4 = ["local", "shadowsocks-service/local-socks4"] # Enable Tun interface protocol for sslocal local-tun = ["local", "shadowsocks-service/local-tun", "ipnet"] +# Enable Fake DNS for sslocal +local-fake-dns = ["local", "shadowsocks-service/local-fake-dns"] # ssurl support outline (ssconf) URL utility-url-outline = ["reqwest"] diff --git a/crates/shadowsocks-service/Cargo.toml b/crates/shadowsocks-service/Cargo.toml index 460355d5..72577c9f 100644 --- a/crates/shadowsocks-service/Cargo.toml +++ b/crates/shadowsocks-service/Cargo.toml @@ -94,6 +94,8 @@ local-tunnel = ["local"] local-socks4 = ["local"] # Enable Tun interface protocol for sslocal local-tun = ["local", "etherparse", "tun", "smoltcp"] +# Enable Fake DNS +local-fake-dns = ["local", "trust-dns", "sled", "prost", "prost-build"] # Enable Stream Cipher Protocol # WARN: Stream Cipher Protocol is proved to be insecure @@ -128,6 +130,8 @@ bytes = "1.6" byte_string = "1.0" byteorder = "1.5" rand = { version = "0.8", features = ["small_rng"] } +sled = { version = "0.34.7", features = ["compression"], optional = true } +prost = { version = "0.11.9", optional = true } futures = "0.3" tokio = { version = "1.5", features = [ @@ -186,6 +190,9 @@ nix = { version = "0.28", features = ["ioctl"] } [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.52", features = ["Win32_Networking_WinSock"] } +[build-dependencies] +prost-build = { version = "0.11.9", optional = true } + [dev-dependencies] byteorder = "1.5" env_logger = "0.11" diff --git a/crates/shadowsocks-service/build.rs b/crates/shadowsocks-service/build.rs new file mode 100644 index 00000000..15b5511d --- /dev/null +++ b/crates/shadowsocks-service/build.rs @@ -0,0 +1,11 @@ +use std::io; + +fn main() -> io::Result<()> { + #[cfg(feature = "local-fake-dns")] + prost_build::compile_protos( + &["src/local/fake_dns/proto/fake_dns.proto"], + &["src/local/fake_dns/proto/"], + )?; + + Ok(()) +} diff --git a/crates/shadowsocks-service/src/config.rs b/crates/shadowsocks-service/src/config.rs index faf85c17..8b86ca11 100644 --- a/crates/shadowsocks-service/src/config.rs +++ b/crates/shadowsocks-service/src/config.rs @@ -62,20 +62,15 @@ use cfg_if::cfg_if; use hickory_resolver::config::{NameServerConfig, Protocol, ResolverConfig}; #[cfg(feature = "local-tun")] use ipnet::IpNet; +#[cfg(feature = "local-fake-dns")] +use ipnet::{Ipv4Net, Ipv6Net}; use log::warn; use serde::{Deserialize, Serialize}; #[cfg(any(feature = "local-tunnel", feature = "local-dns"))] use shadowsocks::relay::socks5::Address; use shadowsocks::{ config::{ - ManagerAddr, - Mode, - ReplayAttackPolicy, - ServerAddr, - ServerConfig, - ServerUser, - ServerUserManager, - ServerWeight, + ManagerAddr, Mode, ReplayAttackPolicy, ServerAddr, ServerConfig, ServerUser, ServerUserManager, ServerWeight, }, crypto::CipherKind, plugin::PluginConfig, @@ -308,6 +303,20 @@ struct SSLocalExtConfig { #[serde(skip_serializing_if = "Option::is_none")] socks5_auth_config_path: Option, + /// Fake DNS + #[cfg(feature = "local-fake-dns")] + #[serde(skip_serializing_if = "Option::is_none")] + pub fake_dns_record_expire_duration: Option, + #[cfg(feature = "local-fake-dns")] + #[serde(skip_serializing_if = "Option::is_none")] + pub fake_dns_ipv4_network: Option, + #[cfg(feature = "local-fake-dns")] + #[serde(skip_serializing_if = "Option::is_none")] + pub fake_dns_ipv6_network: Option, + #[cfg(feature = "local-fake-dns")] + #[serde(skip_serializing_if = "Option::is_none")] + pub fake_dns_database_path: Option, + #[serde(skip_serializing_if = "Option::is_none")] acl: Option, } @@ -760,6 +769,8 @@ pub enum ProtocolType { Dns, #[cfg(feature = "local-tun")] Tun, + #[cfg(feature = "local-fake-dns")] + FakeDns, } impl ProtocolType { @@ -777,6 +788,8 @@ impl ProtocolType { ProtocolType::Dns => "dns", #[cfg(feature = "local-tun")] ProtocolType::Tun => "tun", + #[cfg(feature = "local-fake-dns")] + ProtocolType::FakeDns => "fake-dns", } } @@ -794,6 +807,8 @@ impl ProtocolType { "dns", #[cfg(feature = "local-tun")] "tun", + #[cfg(feature = "local-fake-dns")] + "fake-dns", ] } } @@ -824,6 +839,8 @@ impl FromStr for ProtocolType { "dns" => Ok(ProtocolType::Dns), #[cfg(feature = "local-tun")] "tun" => Ok(ProtocolType::Tun), + #[cfg(feature = "local-fake-dns")] + "fake-dns" => Ok(ProtocolType::FakeDns), _ => Err(ProtocolTypeError), } } @@ -835,6 +852,7 @@ pub struct LocalConfig { /// Listen address for local servers pub addr: Option, + /// Local Protocol pub protocol: ProtocolType, /// Mode @@ -935,6 +953,19 @@ pub struct LocalConfig { /// SOCKS5 Authentication configuration #[cfg(feature = "local")] pub socks5_auth: Socks5AuthConfig, + + /// Fake DNS record expire seconds + #[cfg(feature = "local-fake-dns")] + pub fake_dns_record_expire_duration: Option, + /// Fake DNS IPv4 allocation space + #[cfg(feature = "local-fake-dns")] + pub fake_dns_ipv4_network: Option, + /// Fake DNS IPv6 allocation space + #[cfg(feature = "local-fake-dns")] + pub fake_dns_ipv6_network: Option, + /// Fake DNS storage database path + #[cfg(feature = "local-fake-dns")] + pub fake_dns_database_path: Option, } impl LocalConfig { @@ -991,6 +1022,15 @@ impl LocalConfig { #[cfg(feature = "local")] socks5_auth: Socks5AuthConfig::default(), + + #[cfg(feature = "local-fake-dns")] + fake_dns_record_expire_duration: None, + #[cfg(feature = "local-fake-dns")] + fake_dns_ipv4_network: None, + #[cfg(feature = "local-fake-dns")] + fake_dns_ipv6_network: None, + #[cfg(feature = "local-fake-dns")] + fake_dns_database_path: None, } } @@ -1664,6 +1704,36 @@ impl Config { local_config.socks5_auth = Socks5AuthConfig::load_from_file(&socks5_auth_config_path)?; } + #[cfg(feature = "local-fake-dns")] + { + if let Some(d) = local.fake_dns_record_expire_duration { + local_config.fake_dns_record_expire_duration = Some(Duration::from_secs(d)); + } + if let Some(n) = local.fake_dns_ipv4_network { + match n.parse::() { + Ok(n) => local_config.fake_dns_ipv4_network = Some(n), + Err(..) => { + let err = + Error::new(ErrorKind::Malformed, "invalid `fake_dns_ipv4_network`", None); + return Err(err); + } + } + } + if let Some(n) = local.fake_dns_ipv6_network { + match n.parse::() { + Ok(n) => local_config.fake_dns_ipv6_network = Some(n), + Err(..) => { + let err = + Error::new(ErrorKind::Malformed, "invalid `fake_dns_ipv6_network`", None); + return Err(err); + } + } + } + if let Some(p) = local.fake_dns_database_path { + local_config.fake_dns_database_path = Some(p.into()); + } + } + let mut local_instance = LocalInstanceConfig { config: local_config, acl: None, @@ -2597,6 +2667,18 @@ impl fmt::Display for Config { #[cfg(feature = "local")] socks5_auth_config_path: None, + #[cfg(feature = "local-fake-dns")] + fake_dns_record_expire_duration: local.fake_dns_record_expire_duration.map(|d| d.as_secs()), + #[cfg(feature = "local-fake-dns")] + fake_dns_ipv4_network: local.fake_dns_ipv4_network.map(|n| n.to_string()), + #[cfg(feature = "local-fake-dns")] + fake_dns_ipv6_network: local.fake_dns_ipv6_network.map(|n| n.to_string()), + #[cfg(feature = "local-fake-dns")] + fake_dns_database_path: local + .fake_dns_database_path + .as_ref() + .and_then(|n| n.to_str().map(ToOwned::to_owned)), + acl: local_instance .acl .as_ref() diff --git a/crates/shadowsocks-service/src/local/context.rs b/crates/shadowsocks-service/src/local/context.rs index 5eb542ab..1d282393 100644 --- a/crates/shadowsocks-service/src/local/context.rs +++ b/crates/shadowsocks-service/src/local/context.rs @@ -15,9 +15,14 @@ use shadowsocks::{ }; #[cfg(feature = "local-dns")] use tokio::sync::Mutex; +#[cfg(feature = "local-fake-dns")] +use tokio::sync::RwLock; use crate::{acl::AccessControl, config::SecurityConfig, net::FlowStat}; +#[cfg(feature = "local-fake-dns")] +use super::fake_dns::manager::FakeDnsManager; + /// Local Service Context #[derive(Clone)] pub struct ServiceContext { @@ -34,6 +39,9 @@ pub struct ServiceContext { // For DNS relay's ACL domain name reverse lookup -- whether the IP shall be forwarded #[cfg(feature = "local-dns")] reverse_lookup_cache: Arc>>, + + #[cfg(feature = "local-fake-dns")] + fake_dns_manager: Arc>>>, } impl Default for ServiceContext { @@ -56,6 +64,8 @@ impl ServiceContext { Duration::from_secs(3 * 24 * 60 * 60), 10240, // XXX: It should be enough for a normal user. ))), + #[cfg(feature = "local-fake-dns")] + fake_dns_manager: Arc::new(RwLock::new(None)), } } @@ -180,4 +190,35 @@ impl ServiceContext { let context = Arc::get_mut(&mut self.context).expect("cannot set security on a shared context"); context.set_replay_attack_policy(security.replay_attack.policy); } + + /// Set Fake DNS manager + #[cfg(feature = "local-fake-dns")] + pub async fn set_fake_dns_manager(&self, manager: Arc) { + let mut opt = self.fake_dns_manager.write().await; + assert!(opt.is_none(), "one server instance can have only one fake-dns instance"); + *opt = Some(manager); + } + + /// Fake DNS maps IP to Domain + #[cfg(feature = "local-fake-dns")] + pub async fn try_map_fake_address(&self, addr: &Address) -> Option
{ + match *(self.fake_dns_manager.read().await) { + None => None, + Some(ref mgr) => match addr { + Address::DomainNameAddress(..) => None, + Address::SocketAddress(socket_addr) => { + let ip_addr = socket_addr.ip(); + match mgr.map_ip_domain(ip_addr).await { + Ok(None) => None, + Ok(Some(name)) => { + let new_addr = Address::DomainNameAddress(name.to_string(), socket_addr.port()); + log::trace!("fakedns mapped {} -> {}", addr, new_addr); + Some(new_addr) + } + Err(..) => None, + } + } + }, + } + } } diff --git a/crates/shadowsocks-service/src/local/fake_dns/manager.rs b/crates/shadowsocks-service/src/local/fake_dns/manager.rs new file mode 100644 index 00000000..264235cf --- /dev/null +++ b/crates/shadowsocks-service/src/local/fake_dns/manager.rs @@ -0,0 +1,293 @@ +//! Fake DNS manager + +use std::{ + io::{self, Cursor}, + iter::Cycle, + net::{IpAddr, Ipv4Addr, Ipv6Addr}, + path::Path, + time::{Duration, SystemTime}, +}; + +use hickory_resolver::proto::rr::Name; +use ipnet::{Ipv4AddrRange, Ipv4Net, Ipv6AddrRange, Ipv6Net}; +use log::{trace, warn}; +use prost::Message; +use sled::{Config as SledConfig, Db as SledDatabase}; +use tokio::sync::Mutex; + +use super::proto; + +const FAKE_DNS_MANAGER_STORAGE_VERSION: u32 = 1; + +/// Fake DNS manager +pub struct FakeDnsManager { + db: SledDatabase, + ipv4_network: Mutex>, + ipv6_network: Mutex>, + expire_duration: Duration, +} + +macro_rules! map_domain_ip { + ($self:ident, $domain:ident, $addr_ty:ty, $addr_field:ident, $network_field:ident) => {{ + let name2ip_key = FakeDnsManager::get_name2ip_key($domain); + + loop { + let name2ip_value = $self.db.get(&name2ip_key)?; + + let mut domain_name_mapping = proto::DomainNameMapping::default(); + + if let Some(ref v) = name2ip_value { + domain_name_mapping = proto::DomainNameMapping::decode(&mut Cursor::new(v))?; + + if !domain_name_mapping.$addr_field.is_empty() { + match domain_name_mapping.$addr_field.parse::<$addr_ty>() { + Ok(i) => { + let now = FakeDnsManager::get_current_timestamp(); + let expire_secs = + FakeDnsManager::get_current_timestamp() + $self.expire_duration.as_secs() as i64; + + let mut reallocate = true; + if domain_name_mapping.expire_time >= now { + // Not expired yet. + reallocate = false; + } else { + // Expired. Try to reuse. + + let ip2name_key = FakeDnsManager::get_ip2name_key(i.into()); + let ip2name_value = $self.db.get(&ip2name_key)?; + if let Some(ref v) = ip2name_value { + let mut ip_mapping = proto::IpAddrMapping::decode(&mut Cursor::new(v))?; + if ip_mapping.domain_name == $domain.to_string() { + // Try to extend its expire time + ip_mapping.expire_time = expire_secs; + let nv = ip_mapping.encode_to_vec(); + if let Ok(..) = + $self + .db + .compare_and_swap(&ip2name_key, ip2name_value.as_ref(), Some(nv)) + { + reallocate = false; + } else { + // CAS Failed, retry + continue; + } + } + } + } + + if !reallocate { + domain_name_mapping.expire_time = expire_secs; + let nv = domain_name_mapping.encode_to_vec(); + + // Ignore update error. It is ok if expire_time is updated by another thread. + let _ = $self + .db + .compare_and_swap(&name2ip_key, name2ip_value.as_ref(), Some(nv)); + trace!( + "fakedns mapping {} -> {}, expires {}", + $domain, + i, + domain_name_mapping.expire_time + ); + return Ok((i, $self.expire_duration)); + } + } + Err(..) => { + warn!("failed to parse {}, going to replace", domain_name_mapping.$addr_field); + } + } + } + } + + // Allocate a new IPv4 address for this domain + 'alloc_network: while let Some(ip) = $self.$network_field.lock().await.next() { + let ip2name_key = FakeDnsManager::get_ip2name_key(ip.into()); + + loop { + let ip2name_value = $self.db.get(&ip2name_key)?; + if let Some(ref v) = ip2name_value { + let ip_mapping = proto::IpAddrMapping::decode(&mut Cursor::new(v))?; + + let now = FakeDnsManager::get_current_timestamp(); + if ip_mapping.expire_time > now { + break; + } + } + + let mut ip_mapping = proto::IpAddrMapping::default(); + + let expire_secs = FakeDnsManager::get_current_timestamp() + $self.expire_duration.as_secs() as i64; + ip_mapping.expire_time = expire_secs; + ip_mapping.domain_name = $domain.to_string(); + + let nv = ip_mapping.encode_to_vec(); + + if let Ok(..) = $self.db.compare_and_swap(&ip2name_key, ip2name_value, Some(nv.clone())) { + // Replace name2ip + + domain_name_mapping.$addr_field = ip.to_string(); + domain_name_mapping.expire_time = ip_mapping.expire_time; + let nv = domain_name_mapping.encode_to_vec(); + + if let Ok(..) = $self + .db + .compare_and_swap(&name2ip_key, name2ip_value.as_ref(), Some(nv)) + { + trace!( + "fakedns mapping {} -> {}, expires {} created", + $domain, + ip, + domain_name_mapping.expire_time + ); + + return Ok((ip, $self.expire_duration)); + } else { + // name2ip CAS failed. Some other thread already allocated an address for this name. + let _ = $self.db.remove(&ip2name_key); + break 'alloc_network; + } + } + } + } + } + }}; +} + +impl FakeDnsManager { + pub fn open>( + db_path: P, + ipv4_network: Ipv4Net, + ipv6_network: Ipv6Net, + expire_duration: Duration, + ) -> io::Result { + let db = SledConfig::new() + .cache_capacity(10 * 1024 * 1024) + .use_compression(true) + .mode(sled::Mode::HighThroughput) + .flush_every_ms(Some(1 * 1000)) + .path(db_path) + .open()?; + + let ipv4_network_str = ipv4_network.to_string(); + let ipv6_network_str = ipv6_network.to_string(); + + let mut recreate_database = true; + + let key = "shadowsocks_fakedns_meta"; + if let Some(v) = db.get(key)? { + let c = proto::StorageMeta::decode(&mut Cursor::new(&v))?; + if c.version == FAKE_DNS_MANAGER_STORAGE_VERSION { + if ipv4_network_str != c.ipv4_network || ipv6_network_str != c.ipv6_network { + warn!( + "IPv4 network {} (storage {}), IPv6 network {} (storage {}) not match", + ipv4_network_str, c.ipv4_network, ipv6_network_str, c.ipv6_network + ); + } else { + recreate_database = false; + } + } else { + warn!("storage version {} not match", c.version); + } + } + + if recreate_database { + let _ = db.clear(); + + let mut c = proto::StorageMeta::default(); + c.ipv4_network = ipv4_network_str; + c.ipv6_network = ipv6_network_str; + c.version = FAKE_DNS_MANAGER_STORAGE_VERSION; + + let v = c.encode_to_vec(); + db.insert(key, v)?; + + trace!("FakeDNS database created. {:?}", c); + } + + Ok(FakeDnsManager { + db, + ipv4_network: Mutex::new(ipv4_network.hosts().cycle()), + ipv6_network: Mutex::new(ipv6_network.hosts().cycle()), + expire_duration, + }) + } + + #[inline] + fn get_current_timestamp() -> i64 { + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .expect("SystemTime") + .as_secs() as i64 + } + + #[inline] + fn get_name2ip_key(domain: &Name) -> String { + format!("shadowsocks_fakedns_name2ip_{domain}") + } + + #[inline] + fn get_ip2name_key(ip: IpAddr) -> String { + format!("shadowsocks_fakedns_ip2name_{ip}") + } + + /// Get or create an IPv4 mapping for `domain` + pub async fn map_domain_ipv4(&self, domain: &Name) -> io::Result<(Ipv4Addr, Duration)> { + map_domain_ip!(self, domain, Ipv4Addr, ipv4_addr, ipv4_network) + } + + /// Get or create an IPv6 mapping for `domain` + pub async fn map_domain_ipv6(&self, domain: &Name) -> io::Result<(Ipv6Addr, Duration)> { + map_domain_ip!(self, domain, Ipv6Addr, ipv6_addr, ipv6_network) + } + + /// Get IP mapped domain name + pub async fn map_ip_domain(&self, ip: IpAddr) -> io::Result> { + let ip2name_key = FakeDnsManager::get_ip2name_key(ip); + + let ip2name_value = self.db.get(&ip2name_key)?; + match ip2name_value { + None => Ok(None), + Some(ref v) => { + let mut ip_mapping = proto::IpAddrMapping::decode(&mut Cursor::new(v))?; + + let now = FakeDnsManager::get_current_timestamp(); + if ip_mapping.expire_time >= now { + // Ok. It is not expired yet. Try to extend its expire time. + ip_mapping.expire_time = now + self.expire_duration.as_secs() as i64; + let nv = ip_mapping.encode_to_vec(); + let _ = self + .db + .compare_and_swap(&ip2name_key, ip2name_value.as_ref(), Some(nv))?; + + // Update name2ip's expire time + + let name = match ip_mapping.domain_name.parse::() { + Ok(n) => n, + Err(..) => return Ok(None), + }; + + { + let name2ip_key = FakeDnsManager::get_name2ip_key(&name); + let name2ip_value = self.db.get(&name2ip_key)?; + match name2ip_value { + Some(ref v) => { + let mut domain_name_mapping = proto::DomainNameMapping::decode(&mut Cursor::new(v))?; + domain_name_mapping.expire_time = ip_mapping.expire_time; + let nv = domain_name_mapping.encode_to_vec(); + let _ = self.db.compare_and_swap(&name2ip_key, name2ip_value.as_ref(), Some(nv)); + } + None => { + // Interesting. No name2ip. + return Ok(None); + } + } + } + + Ok(Some(name)) + } else { + Ok(None) + } + } + } + } +} diff --git a/crates/shadowsocks-service/src/local/fake_dns/mod.rs b/crates/shadowsocks-service/src/local/fake_dns/mod.rs new file mode 100644 index 00000000..2e70de2f --- /dev/null +++ b/crates/shadowsocks-service/src/local/fake_dns/mod.rs @@ -0,0 +1,16 @@ +//! Fake DNS +//! +//! Start a DNS resolver server, mapping requested names to local private network addresses. +//! When local server receives proxy request with those mapped addresses, it could translate +//! it back to the original domain names. +//! +//! It normally cooperates with `local-redir` and `local-tun`. + +pub use self::server::{FakeDns, FakeDnsBuilder}; + +pub mod manager; +mod processor; +mod proto; +pub mod server; +mod tcp_server; +mod udp_server; diff --git a/crates/shadowsocks-service/src/local/fake_dns/processor.rs b/crates/shadowsocks-service/src/local/fake_dns/processor.rs new file mode 100644 index 00000000..fb730ace --- /dev/null +++ b/crates/shadowsocks-service/src/local/fake_dns/processor.rs @@ -0,0 +1,64 @@ +//! DNS request processor + +use std::io; + +use hickory_resolver::proto::{ + op::{header::MessageType, response_code::ResponseCode, Message, OpCode}, + rr::{ + rdata::{A, AAAA}, + DNSClass, RData, Record, RecordType, + }, +}; +use log::{debug, trace}; + +use super::manager::FakeDnsManager; + +pub async fn handle_dns_request(req_message: &Message, manager: &FakeDnsManager) -> io::Result { + let mut rsp_message = Message::new(); + rsp_message.set_id(req_message.id()); + rsp_message.set_message_type(MessageType::Response); + rsp_message.set_recursion_desired(false); + rsp_message.set_recursion_available(false); + + if req_message.op_code() != OpCode::Query || req_message.message_type() != MessageType::Query { + rsp_message.set_response_code(ResponseCode::NotImp); + } else { + for query in req_message.queries() { + if query.query_class() != DNSClass::IN { + let record = Record::::with(query.name().clone(), query.query_type(), 0); + rsp_message.add_answer(record); + continue; + } + + match query.query_type() { + RecordType::A => { + let (ip_addr, expire_duration) = manager.map_domain_ipv4(query.name()).await?; + let [a, b, c, d] = ip_addr.octets(); + + let mut record = + Record::::with(query.name().clone(), RecordType::A, expire_duration.as_secs() as u32); + record.set_dns_class(query.query_class()); + record.set_data(Some(RData::A(A::new(a, b, c, d)))); + rsp_message.add_answer(record); + } + RecordType::AAAA => { + let (ip_addr, expire_duration) = manager.map_domain_ipv6(query.name()).await?; + let [a, b, c, d, e, f, g, h] = ip_addr.segments(); + + let mut record = + Record::::with(query.name().clone(), RecordType::AAAA, expire_duration.as_secs() as u32); + record.set_dns_class(query.query_class()); + record.set_data(Some(RData::AAAA(AAAA::new(a, b, c, d, e, f, g, h)))); + rsp_message.add_answer(record); + } + _ => { + debug!("fakedns {} not supported. {:?}", query.query_type(), query); + } + } + } + } + + trace!("QUERY {:?} ANSWER {:?}", req_message, rsp_message); + + Ok(rsp_message) +} diff --git a/crates/shadowsocks-service/src/local/fake_dns/proto/fake_dns.proto b/crates/shadowsocks-service/src/local/fake_dns/proto/fake_dns.proto new file mode 100644 index 00000000..d202213b --- /dev/null +++ b/crates/shadowsocks-service/src/local/fake_dns/proto/fake_dns.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +package shadowsocks_service.local.fake_dns.proto; + +message StorageMeta { + string ipv4_network = 1; // IPv4 allocation pool + string ipv6_network = 2; // IPv6 allocation pool + uint32 version = 3; // Storage Version +} + +// ip2domain_{IP_ADDR} +message IpAddrMapping { + string domain_name = 1; // Original Domain + int64 expire_time = 2; +} + +// domain2ip_{DOMAIN_NAME} +message DomainNameMapping { + string ipv4_addr = 1; // Mapped IPv4 Address + string ipv6_addr = 2; // Mapped IPv6 Address + int64 expire_time = 3; +} diff --git a/crates/shadowsocks-service/src/local/fake_dns/proto/mod.rs b/crates/shadowsocks-service/src/local/fake_dns/proto/mod.rs new file mode 100644 index 00000000..aafe63b5 --- /dev/null +++ b/crates/shadowsocks-service/src/local/fake_dns/proto/mod.rs @@ -0,0 +1,3 @@ +//! FakeDNS protobuf + +include!(concat!(env!("OUT_DIR"), "/shadowsocks_service.local.fake_dns.proto.rs")); diff --git a/crates/shadowsocks-service/src/local/fake_dns/server.rs b/crates/shadowsocks-service/src/local/fake_dns/server.rs new file mode 100644 index 00000000..0c739310 --- /dev/null +++ b/crates/shadowsocks-service/src/local/fake_dns/server.rs @@ -0,0 +1,138 @@ +//! Fake DNS server + +use std::{ + io, + net::{Ipv4Addr, Ipv6Addr}, + path::{Path, PathBuf}, + sync::Arc, + time::Duration, +}; + +use futures::{future, FutureExt}; +use ipnet::{Ipv4Net, Ipv6Net}; +use shadowsocks::config::{Mode, ServerAddr}; + +use crate::local::context::ServiceContext; + +use super::{manager::FakeDnsManager, tcp_server::FakeDnsTcpServer, udp_server::FakeDnsUdpServer}; + +/// Fake DNS builder +pub struct FakeDnsBuilder { + context: Arc, + mode: Mode, + client_addr: ServerAddr, + database_path: PathBuf, + ipv4_network: Ipv4Net, + ipv6_network: Ipv6Net, + expire_duration: Duration, +} + +impl FakeDnsBuilder { + /// Create a new Fake DNS server + pub fn new(client_addr: ServerAddr) -> FakeDnsBuilder { + let context = ServiceContext::new(); + FakeDnsBuilder::with_context(Arc::new(context), client_addr) + } + + /// Create a new Fake DNS server with context + pub fn with_context(context: Arc, client_addr: ServerAddr) -> FakeDnsBuilder { + FakeDnsBuilder { + context, + mode: Mode::TcpAndUdp, + client_addr, + database_path: "shadowsocks-fakedns.sled".into(), + ipv4_network: Ipv4Net::new(Ipv4Addr::new(172, 16, 0, 0), 12).unwrap(), + ipv6_network: Ipv6Net::new(Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 0), 7).unwrap(), + expire_duration: Duration::from_secs(10), + } + } + + /// Set IPv4 network + pub fn set_ipv4_network(&mut self, ipv4_network: Ipv4Net) { + self.ipv4_network = ipv4_network; + } + + /// Set IPv6 network + pub fn set_ipv6_network(&mut self, ipv6_network: Ipv6Net) { + self.ipv6_network = ipv6_network; + } + + /// Set expire duration + pub fn set_expire_duration(&mut self, expire: Duration) { + self.expire_duration = expire; + } + + /// Set database path + pub fn set_database_path>(&mut self, database_path: P) { + self.database_path = database_path.as_ref().to_path_buf(); + } + + /// Build Fake DNS server + pub async fn build(self) -> io::Result { + let manager = FakeDnsManager::open( + &self.database_path, + self.ipv4_network, + self.ipv6_network, + self.expire_duration, + )?; + let manager = Arc::new(manager); + + let mut tcp_server = None; + if self.mode.enable_tcp() { + let server = FakeDnsTcpServer::new(self.context.clone(), &self.client_addr, manager.clone()).await?; + tcp_server = Some(server); + } + + let mut udp_server = None; + if self.mode.enable_udp() { + let server = FakeDnsUdpServer::new(self.context.clone(), &self.client_addr, manager.clone()).await?; + udp_server = Some(server); + } + + Ok(FakeDns { + tcp_server, + udp_server, + manager, + }) + } +} + +/// Fake DNS server instance +pub struct FakeDns { + tcp_server: Option, + udp_server: Option, + manager: Arc, +} + +impl FakeDns { + /// TCP Server instance + pub fn tcp_server(&self) -> Option<&FakeDnsTcpServer> { + self.tcp_server.as_ref() + } + + /// UDP Server instance + pub fn udp_server(&self) -> Option<&FakeDnsUdpServer> { + self.udp_server.as_ref() + } + + /// Get the manager + pub fn clone_manager(&self) -> Arc { + self.manager.clone() + } + + /// Run server + pub async fn run(self) -> io::Result<()> { + let mut vfut = Vec::new(); + + if let Some(tcp_server) = self.tcp_server { + vfut.push(tcp_server.run().boxed()); + } + + if let Some(udp_server) = self.udp_server { + vfut.push(udp_server.run().boxed()); + } + + let (res, ..) = future::select_all(vfut).await; + res + } +} diff --git a/crates/shadowsocks-service/src/local/fake_dns/tcp_server.rs b/crates/shadowsocks-service/src/local/fake_dns/tcp_server.rs new file mode 100644 index 00000000..aea92671 --- /dev/null +++ b/crates/shadowsocks-service/src/local/fake_dns/tcp_server.rs @@ -0,0 +1,164 @@ +//! Fake DNS TCP server + +use std::{ + io::{self, ErrorKind}, + net::SocketAddr, + sync::Arc, + time::Duration, +}; + +use byteorder::{BigEndian, ByteOrder}; +use bytes::{BufMut, BytesMut}; +use hickory_resolver::proto::{ + op::{header::MessageType, response_code::ResponseCode, Message}, + serialize::binary::{BinEncodable, BinEncoder, EncodeMode}, +}; +use log::{error, trace}; +use shadowsocks::{lookup_then, net::TcpListener as ShadowTcpListener, ServerAddr}; +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::TcpStream, + time, +}; + +use crate::local::context::ServiceContext; + +use super::{manager::FakeDnsManager, processor::handle_dns_request}; + +/// Fake DNS TCP server +pub struct FakeDnsTcpServer { + context: Arc, + listener: ShadowTcpListener, + manager: Arc, +} + +impl FakeDnsTcpServer { + pub(crate) async fn new( + context: Arc, + client_config: &ServerAddr, + manager: Arc, + ) -> io::Result { + let listener = match *client_config { + ServerAddr::SocketAddr(ref saddr) => { + ShadowTcpListener::bind_with_opts(saddr, context.accept_opts()).await? + } + ServerAddr::DomainName(ref dname, port) => { + lookup_then!(context.context_ref(), dname, port, |addr| { + ShadowTcpListener::bind_with_opts(&addr, context.accept_opts()).await + })? + .1 + } + }; + + Ok(FakeDnsTcpServer { + context, + listener, + manager, + }) + } + + /// Get TCP local address + pub fn local_addr(&self) -> io::Result { + self.listener.local_addr() + } + + /// Run TCP server loop + pub async fn run(self) -> io::Result<()> { + loop { + let (stream, peer_addr) = match self.listener.accept().await { + Ok(s) => s, + Err(err) => { + error!("failed to accept Fake DNS connection, err: {}", err); + time::sleep(Duration::from_secs(1)).await; + continue; + } + }; + + trace!("Fake DNS accepted TCP client {}", peer_addr); + + let context = self.context.clone(); + let manager = self.manager.clone(); + tokio::spawn(async move { + if let Err(err) = FakeDnsTcpServer::handle_client(context, peer_addr, stream, manager).await { + error!( + "failed to handle Fake DNS tcp client, peer: {}, err: {}", + peer_addr, err + ); + } + }); + } + } + + async fn handle_client( + _context: Arc, + peer_addr: SocketAddr, + mut stream: TcpStream, + manager: Arc, + ) -> io::Result<()> { + let mut length_buf = [0u8; 2]; + let mut message_buf = BytesMut::new(); + + loop { + match stream.read_exact(&mut length_buf).await { + Ok(..) => {} + Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => { + break; + } + Err(err) => { + error!("udp tcp {} read length failed, error: {}", peer_addr, err); + return Err(err); + } + } + + let length = BigEndian::read_u16(&length_buf) as usize; + + message_buf.clear(); + message_buf.reserve(length); + unsafe { + message_buf.advance_mut(length); + } + + match stream.read_exact(&mut message_buf).await { + Ok(..) => {} + Err(err) => { + error!("dns tcp {} read message failed, error: {}", peer_addr, err); + return Err(err); + } + } + + let req_message = match Message::from_vec(&message_buf) { + Ok(m) => m, + Err(err) => { + error!("dns tcp {} parse message failed, error: {}", peer_addr, err); + return Err(err.into()); + } + }; + + let rsp_message = match handle_dns_request(&req_message, &manager).await { + Ok(m) => m, + Err(err) => { + error!("failed to handle DNS request, error: {}", err); + + let mut rsp_message = Message::new(); + rsp_message.set_id(req_message.id()); + rsp_message.set_message_type(MessageType::Response); + rsp_message.set_response_code(ResponseCode::ServFail); + + rsp_message + } + }; + + let mut rsp_buffer = Vec::with_capacity(2 + 512); + rsp_buffer.resize(2, 0); + let mut rsp_encoder = BinEncoder::with_offset(&mut rsp_buffer, 2, EncodeMode::Normal); + rsp_message.emit(&mut rsp_encoder)?; + + let rsp_length = (rsp_buffer.len() - 2) as u16; + BigEndian::write_u16(&mut rsp_buffer[0..2], rsp_length); + + stream.write_all(&rsp_buffer).await?; + } + + Ok(()) + } +} diff --git a/crates/shadowsocks-service/src/local/fake_dns/udp_server.rs b/crates/shadowsocks-service/src/local/fake_dns/udp_server.rs new file mode 100644 index 00000000..6dea1a34 --- /dev/null +++ b/crates/shadowsocks-service/src/local/fake_dns/udp_server.rs @@ -0,0 +1,85 @@ +//! Fake DNS UDP server + +use std::{io, net::SocketAddr, sync::Arc, time::Duration}; + +use hickory_resolver::proto::op::{header::MessageType, response_code::ResponseCode, Message}; +use log::error; +use shadowsocks::{lookup_then, net::UdpSocket as ShadowUdpSocket, ServerAddr}; +use tokio::time; + +use crate::local::context::ServiceContext; + +use super::{manager::FakeDnsManager, processor::handle_dns_request}; + +/// Fake DNS UDP server instance +pub struct FakeDnsUdpServer { + listener: ShadowUdpSocket, + manager: Arc, +} + +impl FakeDnsUdpServer { + pub(crate) async fn new( + context: Arc, + client_config: &ServerAddr, + manager: Arc, + ) -> io::Result { + let listener = match *client_config { + ServerAddr::SocketAddr(ref saddr) => { + ShadowUdpSocket::listen_with_opts(saddr, context.accept_opts()).await? + } + ServerAddr::DomainName(ref dname, port) => { + lookup_then!(context.context_ref(), dname, port, |addr| { + ShadowUdpSocket::listen_with_opts(&addr, context.accept_opts()).await + })? + .1 + } + }; + + Ok(FakeDnsUdpServer { listener, manager }) + } + + /// Get UDP local address + pub fn local_addr(&self) -> io::Result { + self.listener.local_addr() + } + + /// Start server accept loop + pub async fn run(self) -> io::Result<()> { + let mut buffer = [0u8; 65535]; + loop { + let (n, peer_addr) = match self.listener.recv_from(&mut buffer).await { + Ok(n) => n, + Err(err) => { + error!("fakedns UDP recv_from failed, error: {}", err); + time::sleep(Duration::from_secs(1)).await; + continue; + } + }; + + let req_message = match Message::from_vec(&buffer[..n]) { + Ok(m) => m, + Err(err) => { + error!("failed to parse DNS request, error: {}", err); + continue; + } + }; + + let rsp_message = match handle_dns_request(&req_message, &self.manager).await { + Ok(m) => m, + Err(err) => { + error!("failed to handle DNS request, error: {}", err); + + let mut rsp_message = Message::new(); + rsp_message.set_id(req_message.id()); + rsp_message.set_message_type(MessageType::Response); + rsp_message.set_response_code(ResponseCode::ServFail); + + rsp_message + } + }; + + let rsp_buffer = rsp_message.to_vec()?; + let _ = self.listener.send_to(&rsp_buffer, peer_addr).await; + } + } +} diff --git a/crates/shadowsocks-service/src/local/mod.rs b/crates/shadowsocks-service/src/local/mod.rs index b274874a..760cc6fc 100644 --- a/crates/shadowsocks-service/src/local/mod.rs +++ b/crates/shadowsocks-service/src/local/mod.rs @@ -31,6 +31,8 @@ use self::{ #[cfg(feature = "local-dns")] use self::dns::{Dns, DnsBuilder}; +#[cfg(feature = "local-fake-dns")] +use self::fake_dns::{FakeDns, FakeDnsBuilder}; #[cfg(feature = "local-http")] use self::http::{Http, HttpBuilder}; #[cfg(feature = "local-redir")] @@ -44,6 +46,8 @@ use self::tunnel::{Tunnel, TunnelBuilder}; pub mod context; #[cfg(feature = "local-dns")] pub mod dns; +#[cfg(feature = "local-fake-dns")] +pub mod fake_dns; #[cfg(feature = "local-http")] pub mod http; pub mod loadbalancing; @@ -97,6 +101,8 @@ pub struct Server { dns_servers: Vec, #[cfg(feature = "local-redir")] redir_servers: Vec, + #[cfg(feature = "local-fake-dns")] + fake_dns_servers: Vec, #[cfg(feature = "local-flow-stat")] local_stat_addr: Option, #[cfg(feature = "local-flow-stat")] @@ -239,6 +245,8 @@ impl Server { dns_servers: Vec::new(), #[cfg(feature = "local-redir")] redir_servers: Vec::new(), + #[cfg(feature = "local-fake-dns")] + fake_dns_servers: Vec::new(), #[cfg(feature = "local-flow-stat")] local_stat_addr: config.local_stat_addr, #[cfg(feature = "local-flow-stat")] @@ -481,6 +489,32 @@ impl Server { let server = builder.build().await?; local_server.tun_servers.push(server); } + #[cfg(feature = "local-fake-dns")] + ProtocolType::FakeDns => { + let client_addr = match local_config.addr { + Some(a) => a, + None => return Err(io::Error::new(ErrorKind::Other, "dns requires local address")), + }; + + let mut builder = FakeDnsBuilder::new(client_addr); + if let Some(n) = local_config.fake_dns_ipv4_network { + builder.set_ipv4_network(n); + } + if let Some(n) = local_config.fake_dns_ipv6_network { + builder.set_ipv6_network(n); + } + if let Some(exp) = local_config.fake_dns_record_expire_duration { + builder.set_expire_duration(exp); + } + if let Some(p) = local_config.fake_dns_database_path { + builder.set_database_path(p); + } + let server = builder.build().await?; + #[cfg(feature = "local-fake-dns")] + context.set_fake_dns_manager(server.clone_manager()).await; + + local_server.fake_dns_servers.push(server); + } } } @@ -520,6 +554,11 @@ impl Server { vfut.push(ServerHandle(tokio::spawn(svr.run()))); } + #[cfg(feature = "local-fake-dns")] + for svr in self.fake_dns_servers { + vfut.push(ServerHandle(tokio::spawn(svr.run()))); + } + #[cfg(feature = "local-flow-stat")] if let Some(stat_addr) = self.local_stat_addr { // For Android's flow statistic @@ -571,6 +610,12 @@ impl Server { pub fn redir_servers(&self) -> &[Redir] { &self.redir_servers } + + /// Get Fake DNS instances + #[cfg(feature = "local-fake-dns")] + pub fn fake_dns_servers(&self) -> &[FakeDns] { + &self.fake_dns_servers + } } #[cfg(feature = "local-flow-stat")] diff --git a/crates/shadowsocks-service/src/local/net/tcp/auto_proxy_stream.rs b/crates/shadowsocks-service/src/local/net/tcp/auto_proxy_stream.rs index 1c04e9ae..fd225cab 100644 --- a/crates/shadowsocks-service/src/local/net/tcp/auto_proxy_stream.rs +++ b/crates/shadowsocks-service/src/local/net/tcp/auto_proxy_stream.rs @@ -54,7 +54,12 @@ impl AutoProxyClientStream { A: Into
, { // Connect directly. - let addr = addr.into(); + #[cfg_attr(not(feature = "local-fake-dns"), allow(unused_mut))] + let mut addr = addr.into(); + #[cfg(feature = "local-fake-dns")] + if let Some(mapped_addr) = context.try_map_fake_address(&addr).await { + addr = mapped_addr; + } let stream = TcpStream::connect_remote_with_opts(context.context_ref(), &addr, context.connect_opts_ref()).await?; Ok(AutoProxyClientStream::Bypassed(stream)) @@ -69,6 +74,12 @@ impl AutoProxyClientStream { where A: Into
, { + #[cfg_attr(not(feature = "local-fake-dns"), allow(unused_mut))] + let mut addr = addr.into(); + #[cfg(feature = "local-fake-dns")] + if let Some(mapped_addr) = context.try_map_fake_address(&addr).await { + addr = mapped_addr; + } let flow_stat = context.flow_stat(); let stream = match ProxyClientStream::connect_with_opts_map( context.context(), diff --git a/crates/shadowsocks-service/src/local/net/udp/association.rs b/crates/shadowsocks-service/src/local/net/udp/association.rs index df34c8e8..758db7d5 100644 --- a/crates/shadowsocks-service/src/local/net/udp/association.rs +++ b/crates/shadowsocks-service/src/local/net/udp/association.rs @@ -29,9 +29,7 @@ use shadowsocks::{ use crate::{ local::{context::ServiceContext, loadbalancing::PingBalancer}, net::{ - packet_window::PacketWindowFilter, - MonProxySocket, - UDP_ASSOCIATION_KEEP_ALIVE_CHANNEL_SIZE, + packet_window::PacketWindowFilter, MonProxySocket, UDP_ASSOCIATION_KEEP_ALIVE_CHANNEL_SIZE, UDP_ASSOCIATION_SEND_CHANNEL_SIZE, }, }; @@ -98,7 +96,13 @@ where } /// Sends `data` from `peer_addr` to `target_addr` - pub async fn send_to(&mut self, peer_addr: SocketAddr, target_addr: Address, data: &[u8]) -> io::Result<()> { + #[cfg_attr(not(feature = "local-fake-dns"), allow(unused_mut))] + pub async fn send_to(&mut self, peer_addr: SocketAddr, mut target_addr: Address, data: &[u8]) -> io::Result<()> { + #[cfg(feature = "local-fake-dns")] + if let Some(mapped_addr) = self.context.try_map_fake_address(&target_addr).await { + target_addr = mapped_addr; + } + // Check or (re)create an association if let Some(assoc) = self.assoc_map.get(&peer_addr) { diff --git a/src/service/local.rs b/src/service/local.rs index 64cad9b2..4fad3670 100644 --- a/src/service/local.rs +++ b/src/service/local.rs @@ -443,6 +443,43 @@ pub fn define_command_line_options(mut app: Command) -> Command { } } + #[cfg(feature = "local-fake-dns")] + { + app = app + .arg( + Arg::new("FAKE_DNS_RECORD_EXPIRE_DURATION") + .long("fake-dns-record-expire-duration") + .num_args(1) + .action(ArgAction::Set) + .value_parser(clap::value_parser!(u64)) + .help("Fake DNS record expire duration in seconds"), + ) + .arg( + Arg::new("FAKE_DNS_IPV4_NETWORK") + .long("fake-dns-ipv4-network") + .num_args(1) + .action(ArgAction::Set) + .value_parser(vparser::parse_ipnet) + .help("Fake DNS IPv4 address network"), + ) + .arg( + Arg::new("FAKE_DNS_IPV6_NETWORK") + .long("fake-dns-ipv6-network") + .num_args(1) + .action(ArgAction::Set) + .value_parser(vparser::parse_ipnet) + .help("Fake DNS IPv6 address network"), + ) + .arg( + Arg::new("FAKE_DNS_DATABASE_PATH") + .long("fake-dns-database-path") + .num_args(1) + .action(ArgAction::Set) + .value_hint(ValueHint::AnyPath) + .help("Fake DNS database storage path"), + ); + } + #[cfg(unix)] { app = app @@ -728,6 +765,24 @@ pub fn create(matches: &ArgMatches) -> Result<(Runtime, impl Future("FAKE_DNS_RECORD_EXPIRE_DURATION") { + local_config.fake_dns_record_expire_duration = Some(Duration::from_secs(*d)); + } + if let Some(n) = matches.get_one::("FAKE_DNS_IPV4_NETWORK") { + local_config.fake_dns_ipv4_network = Some(*n); + } + if let Some(n) = matches.get_one::("FAKE_DNS_IPV6_NETWORK") { + local_config.fake_dns_ipv6_network = Some(*n); + } + if let Some(p) = matches.get_one::("FAKE_DNS_DATABASE_PATH").cloned() { + local_config.fake_dns_database_path = Some(p); + } + } + if matches.get_flag("UDP_ONLY") { local_config.mode = Mode::UdpOnly; }