From 2dff4ec4dac42115ae9f18e51048816c82241df6 Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Sun, 12 Mar 2023 17:33:05 +0800 Subject: [PATCH] trust-dns setsockopt with outbound socket configs Outbound configurations, like outbound-fwmark, outbound-bind-interface, outbound-bind-addr, ... will also applies to the TCP/UDP sockets created by trust-dns DNS resolver. NOTE: On Android platform, DNS sockets will also be protected. --- Cargo.lock | 190 ++++++++---------- Cargo.toml | 4 +- crates/shadowsocks-service/Cargo.toml | 7 +- crates/shadowsocks-service/src/config.rs | 22 +- crates/shadowsocks-service/src/dns/mod.rs | 4 +- .../src/local/dns/dns_resolver.rs | 6 +- .../src/local/dns/server.rs | 16 +- crates/shadowsocks/Cargo.toml | 5 +- .../shadowsocks/src/dns_resolver/resolver.rs | 58 +++--- .../src/dns_resolver/trust_dns_resolver.rs | 97 ++++++++- .../src/net/sys/unix/bsd/freebsd.rs | 15 +- .../shadowsocks/src/net/sys/unix/bsd/macos.rs | 16 +- .../shadowsocks/src/net/sys/unix/linux/mod.rs | 14 +- crates/shadowsocks/src/net/sys/unix/others.rs | 11 +- crates/shadowsocks/src/net/sys/windows/mod.rs | 33 ++- crates/shadowsocks/src/net/udp.rs | 17 +- src/service/local.rs | 6 +- 17 files changed, 325 insertions(+), 196 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 807d48f8fdf8..9d4a718e5953 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,42 +72,51 @@ dependencies = [ [[package]] name = "anstream" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f" +checksum = "9e579a7752471abc2a8268df8b20005e3eadd975f585398f17efcfd8d4927371" dependencies = [ "anstyle", "anstyle-parse", + "anstyle-query", "anstyle-wincon", - "concolor-override", - "concolor-query", + "colorchoice", "is-terminal", "utf8parse", ] [[package]] name = "anstyle" -version = "0.3.5" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" [[package]] name = "anstyle-parse" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" dependencies = [ "utf8parse", ] +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "anstyle-wincon" -version = "0.2.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa" +checksum = "4bcd8291a340dd8ac70e18878bc4501dd7b4ff970cfa21c207d36ece51ea88fd" dependencies = [ "anstyle", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -142,7 +151,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -343,18 +352,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.2.1" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3" +checksum = "9b802d85aaf3a1cdb02b224ba472ebdea62014fccfcb269b95a4d76443b5ee5a" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.2.1" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f" +checksum = "14a1a858f532119338887a4b8e1af9c60de8249cd7bafd68036a489e261e37b6" dependencies = [ "anstream", "anstyle", @@ -390,19 +399,10 @@ dependencies = [ ] [[package]] -name = "concolor-override" +name = "colorchoice" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f" - -[[package]] -name = "concolor-query" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf" -dependencies = [ - "windows-sys 0.45.0", -] +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "const-oid" @@ -449,9 +449,9 @@ checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52" [[package]] name = "crossbeam-channel" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -522,7 +522,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -539,7 +539,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -559,9 +559,9 @@ checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" [[package]] name = "defmt" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03193cde597714ff8a5005ccd61cd1b7aff5616eaca7c67905982cb6f347ff4" +checksum = "956673bd3cb347512bf988d1e8d89ac9a82b64f6eec54d3c01c3529dac019882" dependencies = [ "bitflags", "defmt-macros", @@ -731,13 +731,13 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -770,14 +770,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" +checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" dependencies = [ "cfg-if", "libc", "redox_syscall 0.2.16", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -875,7 +875,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -920,9 +920,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" dependencies = [ "cfg-if", "libc", @@ -941,9 +941,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" dependencies = [ "bytes", "fnv", @@ -1078,9 +1078,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.25" +version = "0.14.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" +checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" dependencies = [ "bytes", "futures-channel", @@ -1124,17 +1124,6 @@ dependencies = [ "cxx-build", ] -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.3.0" @@ -1195,13 +1184,13 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" dependencies = [ "hermit-abi 0.3.1", "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1239,14 +1228,14 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256017f749ab3117e93acb91063009e1f1bb56d03965b14c2c8df4eb02c524d8" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1437,12 +1426,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "md-5" version = "0.10.5" @@ -1581,9 +1564,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.49" +version = "0.10.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d2f106ab837a24e03672c59b1239669a0596406ff657c3c0835b6b7f0f35a33" +checksum = "7e30d8bc91859781f0a943411186324d580f2bbeb71b452fe91ae344806af3f1" dependencies = [ "bitflags", "cfg-if", @@ -1602,7 +1585,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -1613,9 +1596,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.84" +version = "0.9.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a20eace9dc2d82904039cb76dcf50fb1a0bba071cfd1629720b5d6f1ddba0fa" +checksum = "0d3d193fb1488ad46ffe3aaabc912cc931d02ee8518fe2959aea8ef52718b0c0" dependencies = [ "cc", "libc", @@ -1711,7 +1694,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -2031,16 +2014,16 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.7" +version = "0.37.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aae838e49b3d63e9274e1c01833cc8139d3fec468c3b84688c628f44b1ae11d" +checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -2198,9 +2181,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.159" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] @@ -2217,20 +2200,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.159" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] name = "serde_json" -version = "1.0.95" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", @@ -2285,7 +2268,7 @@ dependencies = [ [[package]] name = "shadowsocks" -version = "1.15.3" +version = "1.16.0" dependencies = [ "aes", "arc-swap", @@ -2311,7 +2294,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "shadowsocks-crypto", - "socket2 0.5.1", + "socket2 0.5.2", "spin 0.9.8", "thiserror", "tokio", @@ -2346,7 +2329,7 @@ dependencies = [ [[package]] name = "shadowsocks-rust" -version = "1.15.3" +version = "1.16.0" dependencies = [ "base64", "build-time", @@ -2382,7 +2365,7 @@ dependencies = [ [[package]] name = "shadowsocks-service" -version = "1.15.3" +version = "1.16.0" dependencies = [ "arc-swap", "async-trait", @@ -2394,7 +2377,7 @@ dependencies = [ "etherparse", "futures", "hyper", - "idna 0.3.0", + "idna", "ipnet", "iprange", "json5", @@ -2411,7 +2394,7 @@ dependencies = [ "serde", "shadowsocks", "smoltcp", - "socket2 0.5.1", + "socket2 0.5.2", "spin 0.9.8", "thiserror", "tokio", @@ -2508,12 +2491,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc8d618c6641ae355025c449427f9e96b98abf99a772be3cef6708d15c77147a" +checksum = "6d283f86695ae989d1e18440a943880967156325ba025f05049946bff47bcc2b" dependencies = [ "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -2578,9 +2561,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.13" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" dependencies = [ "proc-macro2", "quote", @@ -2657,7 +2640,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -2724,7 +2707,7 @@ checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.15", ] [[package]] @@ -2862,8 +2845,7 @@ dependencies = [ [[package]] name = "trust-dns-proto" version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" +source = "git+https://github.com/bluejekyll/trust-dns.git#c551ebb45a4a15343b8305193fece2e5c23a84ed" dependencies = [ "async-trait", "bytes", @@ -2875,7 +2857,7 @@ dependencies = [ "futures-util", "h2", "http", - "idna 0.2.3", + "idna", "ipnet", "lazy_static", "rand", @@ -2896,8 +2878,7 @@ dependencies = [ [[package]] name = "trust-dns-resolver" version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe" +source = "git+https://github.com/bluejekyll/trust-dns.git#c551ebb45a4a15343b8305193fece2e5c23a84ed" dependencies = [ "cfg-if", "futures-util", @@ -2905,6 +2886,7 @@ dependencies = [ "lazy_static", "lru-cache", "parking_lot", + "rand", "resolv-conf", "rustls 0.20.8", "serde", @@ -3019,7 +3001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ "form_urlencoded", - "idna 0.3.0", + "idna", "percent-encoding", "serde", ] diff --git a/Cargo.toml b/Cargo.toml index 468f806ae908..2435bb483e8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shadowsocks-rust" -version = "1.15.3" +version = "1.16.0" authors = ["Shadowsocks Contributors"] description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls." repository = "https://github.com/shadowsocks/shadowsocks-rust" @@ -167,7 +167,7 @@ jemallocator = { version = "0.5", optional = true } snmalloc-rs = { version = "0.3", optional = true } rpmalloc = { version = "0.2", optional = true } -shadowsocks-service = { version = "1.15.0", path = "./crates/shadowsocks-service" } +shadowsocks-service = { version = "1.16.0", path = "./crates/shadowsocks-service" } [target.'cfg(unix)'.dependencies] daemonize = "0.5" diff --git a/crates/shadowsocks-service/Cargo.toml b/crates/shadowsocks-service/Cargo.toml index 9b8a079b12c1..448de45ebade 100644 --- a/crates/shadowsocks-service/Cargo.toml +++ b/crates/shadowsocks-service/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shadowsocks-service" -version = "1.15.3" +version = "1.16.0" authors = ["Shadowsocks Contributors"] description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls." repository = "https://github.com/shadowsocks/shadowsocks-rust" @@ -107,7 +107,8 @@ libc = "0.2.141" hyper = { version = "0.14.25", optional = true, features = ["full"] } tower = { version = "0.4", optional = true } -trust-dns-resolver = { version = "0.22", optional = true, features = ["serde-config"] } +# trust-dns-resolver = { version = "0.22", optional = true, features = ["serde-config"] } +trust-dns-resolver = { git = "https://github.com/bluejekyll/trust-dns.git", optional = true, features = ["serde-config"] } idna = "0.3" ipnet = "2.7" @@ -121,7 +122,7 @@ smoltcp = { version = "0.9", optional = true, default-features = false, features serde = { version = "1.0", features = ["derive"] } json5 = "0.4" -shadowsocks = { version = "1.15.3", path = "../shadowsocks", default-features = false } +shadowsocks = { version = "1.16.0", path = "../shadowsocks", default-features = false } # Just for the ioctl call macro [target.'cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))'.dependencies] diff --git a/crates/shadowsocks-service/src/config.rs b/crates/shadowsocks-service/src/config.rs index 66dc93650435..27f86aa8dda8 100644 --- a/crates/shadowsocks-service/src/config.rs +++ b/crates/shadowsocks-service/src/config.rs @@ -2112,26 +2112,12 @@ impl Config { }; if protocol.enable_udp() { - c.add_name_server(NameServerConfig { - socket_addr, - protocol: Protocol::Udp, - tls_dns_name: None, - trust_nx_responses: false, - #[cfg(any(feature = "dns-over-tls", feature = "dns-over-https"))] - tls_config: None, - bind_addr: None, - }); + let ns_config = NameServerConfig::new(socket_addr, Protocol::Udp); + c.add_name_server(ns_config); } if protocol.enable_tcp() { - c.add_name_server(NameServerConfig { - socket_addr, - protocol: Protocol::Tcp, - tls_dns_name: None, - trust_nx_responses: false, - #[cfg(any(feature = "dns-over-tls", feature = "dns-over-https"))] - tls_config: None, - bind_addr: None, - }); + let ns_config = NameServerConfig::new(socket_addr, Protocol::Tcp); + c.add_name_server(ns_config); } } diff --git a/crates/shadowsocks-service/src/dns/mod.rs b/crates/shadowsocks-service/src/dns/mod.rs index d6021ff0a763..397608636501 100644 --- a/crates/shadowsocks-service/src/dns/mod.rs +++ b/crates/shadowsocks-service/src/dns/mod.rs @@ -23,7 +23,7 @@ pub async fn build_dns_resolver(dns: DnsConfig, ipv6_first: bool, connect_opts: }; if !force_system_builtin { - return match DnsResolver::trust_dns_system_resolver(ipv6_first).await { + return match DnsResolver::trust_dns_system_resolver(connect_opts.clone()).await { Ok(r) => Some(r), Err(err) => { warn!( @@ -41,7 +41,7 @@ pub async fn build_dns_resolver(dns: DnsConfig, ipv6_first: bool, connect_opts: None } #[cfg(feature = "trust-dns")] - DnsConfig::TrustDns(dns) => match DnsResolver::trust_dns_resolver(dns, ipv6_first).await { + DnsConfig::TrustDns(dns) => match DnsResolver::trust_dns_resolver(dns, connect_opts.clone()).await { Ok(r) => Some(r), Err(err) => { use log::warn; diff --git a/crates/shadowsocks-service/src/local/dns/dns_resolver.rs b/crates/shadowsocks-service/src/local/dns/dns_resolver.rs index 30d944298731..47ee56d80123 100644 --- a/crates/shadowsocks-service/src/local/dns/dns_resolver.rs +++ b/crates/shadowsocks-service/src/local/dns/dns_resolver.rs @@ -2,7 +2,7 @@ use std::{ io::{self, ErrorKind}, - net::SocketAddr, + net::{Ipv4Addr, Ipv6Addr, SocketAddr}, }; use async_trait::async_trait; @@ -175,8 +175,8 @@ fn store_dns(res: Message, port: u16) -> Vec { let mut vaddr = Vec::new(); for record in res.answers() { match record.data() { - Some(RData::A(addr)) => vaddr.push(SocketAddr::new((*addr).into(), port)), - Some(RData::AAAA(addr)) => vaddr.push(SocketAddr::new((*addr).into(), port)), + Some(RData::A(addr)) => vaddr.push(SocketAddr::new(Ipv4Addr::from(*addr).into(), port)), + Some(RData::AAAA(addr)) => vaddr.push(SocketAddr::new(Ipv6Addr::from(*addr).into(), port)), Some(rdata) => { trace!("skipped rdata {:?}", rdata); } diff --git a/crates/shadowsocks-service/src/local/dns/server.rs b/crates/shadowsocks-service/src/local/dns/server.rs index 4040d652a745..cbec19f43dd0 100644 --- a/crates/shadowsocks-service/src/local/dns/server.rs +++ b/crates/shadowsocks-service/src/local/dns/server.rs @@ -413,8 +413,8 @@ fn should_forward_by_response( return true; } let forward = match $rec.data() { - Some(RData::A(ip)) => acl.check_ip_in_proxy_list(&IpAddr::V4(*ip)), - Some(RData::AAAA(ip)) => acl.check_ip_in_proxy_list(&IpAddr::V6(*ip)), + Some(RData::A(ip)) => acl.check_ip_in_proxy_list(&IpAddr::V4((*ip).into())), + Some(RData::AAAA(ip)) => acl.check_ip_in_proxy_list(&IpAddr::V6((*ip).into())), // MX records cause type A additional section processing for the host specified by EXCHANGE. Some(RData::MX(mx)) => examine_name!(mx.exchange(), $is_answer), // NS records cause both the usual additional section processing to locate a type A record... @@ -498,8 +498,16 @@ impl DnsClient { for rec in result.answers() { trace!("dns answer: {:?}", rec); match rec.data() { - Some(RData::A(ip)) => self.context.add_to_reverse_lookup_cache((*ip).into(), forward).await, - Some(RData::AAAA(ip)) => self.context.add_to_reverse_lookup_cache((*ip).into(), forward).await, + Some(RData::A(ip)) => { + self.context + .add_to_reverse_lookup_cache(Ipv4Addr::from(*ip).into(), forward) + .await + } + Some(RData::AAAA(ip)) => { + self.context + .add_to_reverse_lookup_cache(Ipv6Addr::from(*ip).into(), forward) + .await + } _ => (), } } diff --git a/crates/shadowsocks/Cargo.toml b/crates/shadowsocks/Cargo.toml index 9bca0ca9e693..9755880f8d0a 100644 --- a/crates/shadowsocks/Cargo.toml +++ b/crates/shadowsocks/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shadowsocks" -version = "1.15.3" +version = "1.16.0" authors = ["Shadowsocks Contributors"] description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls." repository = "https://github.com/shadowsocks/shadowsocks-rust" @@ -68,7 +68,8 @@ socket2 = { version = "0.5", features = ["all"] } tokio = { version = "1.9.0", features = ["io-util", "macros", "net", "parking_lot", "process", "rt", "sync", "time"] } tokio-tfo = "0.2.0" -trust-dns-resolver = { version = "0.22", optional = true } +# trust-dns-resolver = { version = "0.22", optional = true } +trust-dns-resolver = { git = "https://github.com/bluejekyll/trust-dns.git", optional = true } arc-swap = { version = "1.6", optional = true } notify = { version = "5.1.0", optional = true } diff --git a/crates/shadowsocks/src/dns_resolver/resolver.rs b/crates/shadowsocks/src/dns_resolver/resolver.rs index 305da0c9e6a8..beb23687c03f 100644 --- a/crates/shadowsocks/src/dns_resolver/resolver.rs +++ b/crates/shadowsocks/src/dns_resolver/resolver.rs @@ -20,7 +20,13 @@ use tokio::net::lookup_host; #[cfg(feature = "trust-dns")] use tokio::task::JoinHandle; #[cfg(feature = "trust-dns")] -use trust_dns_resolver::{config::ResolverConfig, TokioAsyncResolver}; +use trust_dns_resolver::config::ResolverConfig; + +#[cfg(feature = "trust-dns")] +use crate::net::ConnectOpts; + +#[cfg(feature = "trust-dns")] +use super::trust_dns_resolver::DnsResolver as TrustDnsResolver; /// Abstract DNS resolver #[async_trait] @@ -31,8 +37,8 @@ pub trait DnsResolve { #[cfg(feature = "trust-dns")] pub struct TrustDnsSystemResolver { - resolver: ArcSwap, - ipv6_first: bool, + resolver: ArcSwap, + connect_opts: ConnectOpts, } /// Collections of DNS resolver @@ -44,11 +50,12 @@ pub enum DnsResolver { #[cfg(feature = "trust-dns")] TrustDnsSystem { inner: Arc, + #[cfg(all(feature = "trust-dns", unix, not(target_os = "android")))] abortable: JoinHandle<()>, }, /// Trust-DNS resolver #[cfg(feature = "trust-dns")] - TrustDns(TokioAsyncResolver), + TrustDns(TrustDnsResolver), /// Customized Resolver Custom(Box), } @@ -75,6 +82,7 @@ impl Debug for DnsResolver { #[cfg(feature = "trust-dns")] impl Drop for DnsResolver { fn drop(&mut self) { + #[cfg(all(feature = "trust-dns", unix, not(target_os = "android")))] if let DnsResolver::TrustDnsSystem { ref abortable, .. } = *self { abortable.abort(); } @@ -187,7 +195,7 @@ async fn trust_dns_notify_update_dns(resolver: Arc) -> n // Update once for all those Modify events time::sleep(Duration::from_secs(1)).await; - match create_resolver(None, resolver.ipv6_first).await { + match create_resolver(None, resolver.connect_opts.clone()).await { Ok(r) => { debug!("auto-reload {DNS_RESOLV_FILE_PATH}"); @@ -208,12 +216,6 @@ async fn trust_dns_notify_update_dns(resolver: Arc) -> n Ok(()) } -#[cfg(all(feature = "trust-dns", any(not(unix), target_os = "android")))] -async fn trust_dns_notify_update_dns(resolver: Arc) -> notify::Result<()> { - let _ = resolver.ipv6_first; // use it for supressing warning - futures::future::pending().await -} - impl DnsResolver { /// Use system DNS resolver. Tokio will call `getaddrinfo` in blocking pool. pub fn system_resolver() -> DnsResolver { @@ -224,33 +226,39 @@ impl DnsResolver { /// /// On *nix system, it will try to read configurations from `/etc/resolv.conf`. #[cfg(feature = "trust-dns")] - pub async fn trust_dns_system_resolver(ipv6_first: bool) -> io::Result { + pub async fn trust_dns_system_resolver(connect_opts: ConnectOpts) -> io::Result { use super::trust_dns_resolver::create_resolver; - let resolver = create_resolver(None, ipv6_first).await?; + let resolver = create_resolver(None, connect_opts.clone()).await?; let inner = Arc::new(TrustDnsSystemResolver { resolver: ArcSwap::from(Arc::new(resolver)), - ipv6_first, + connect_opts, }); - let abortable = { - let inner = inner.clone(); - tokio::spawn(async { - if let Err(err) = trust_dns_notify_update_dns(inner).await { - error!("failed to watch DNS system configuration changes, error: {}", err); - } - }) - }; + cfg_if! { + if #[cfg(all(feature = "trust-dns", unix, not(target_os = "android")))] { + let abortable = { + let inner = inner.clone(); + tokio::spawn(async { + if let Err(err) = trust_dns_notify_update_dns(inner).await { + error!("failed to watch DNS system configuration changes, error: {}", err); + } + }) + }; - Ok(DnsResolver::TrustDnsSystem { inner, abortable }) + Ok(DnsResolver::TrustDnsSystem { inner, abortable }) + } else { + Ok(DnsResolver::TrustDnsSystem { inner }) + } + } } /// Use trust-dns DNS resolver (with DNS cache) #[cfg(feature = "trust-dns")] - pub async fn trust_dns_resolver(dns: ResolverConfig, ipv6_first: bool) -> io::Result { + pub async fn trust_dns_resolver(dns: ResolverConfig, connect_opts: ConnectOpts) -> io::Result { use super::trust_dns_resolver::create_resolver; - Ok(DnsResolver::TrustDns(create_resolver(Some(dns), ipv6_first).await?)) + Ok(DnsResolver::TrustDns(create_resolver(Some(dns), connect_opts).await?)) } /// Custom DNS resolver diff --git a/crates/shadowsocks/src/dns_resolver/trust_dns_resolver.rs b/crates/shadowsocks/src/dns_resolver/trust_dns_resolver.rs index 5dd8818c3de6..bd01abf97abe 100644 --- a/crates/shadowsocks/src/dns_resolver/trust_dns_resolver.rs +++ b/crates/shadowsocks/src/dns_resolver/trust_dns_resolver.rs @@ -1,15 +1,102 @@ //! Asynchronous DNS resolver +use std::{ + future::Future, + io, + net::SocketAddr, + ops::Deref, + pin::Pin, + task::{Context, Poll}, +}; + use cfg_if::cfg_if; +use futures::ready; use log::trace; +use tokio::{io::ReadBuf, net::UdpSocket}; use trust_dns_resolver::{ config::{LookupIpStrategy, ResolverConfig, ResolverOpts}, error::ResolveResult, - TokioAsyncResolver, + name_server::RuntimeProvider, + proto::{iocompat::AsyncIoTokioAsStd, udp::DnsUdpSocket, TokioTime}, + AsyncResolver, + TokioHandle, }; +use crate::net::{tcp::TcpStream as ShadowTcpStream, udp::UdpSocket as ShadowUdpSocket, ConnectOpts}; + +/// Shadowsocks trust-dns Runtime Provider +#[derive(Clone)] +pub struct ShadowDnsProvider { + handle: TokioHandle, + connect_opts: ConnectOpts, +} + +impl ShadowDnsProvider { + fn new(connect_opts: ConnectOpts) -> ShadowDnsProvider { + ShadowDnsProvider { + handle: TokioHandle::default(), + connect_opts, + } + } +} + +impl DnsUdpSocket for ShadowUdpSocket { + type Time = TokioTime; + + #[inline] + fn poll_recv_from(&self, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll> { + let udp: &UdpSocket = self.deref(); + + let mut read_buf = ReadBuf::new(buf); + let recv_addr = ready!(udp.poll_recv_from(cx, &mut read_buf))?; + Ok((read_buf.filled().len(), recv_addr)).into() + } + + #[inline] + fn poll_send_to(&self, cx: &mut Context<'_>, buf: &[u8], target: SocketAddr) -> Poll> { + let udp: &UdpSocket = self.deref(); + udp.poll_send_to(cx, buf, target) + } +} + +impl RuntimeProvider for ShadowDnsProvider { + type Handle = TokioHandle; + type Tcp = AsyncIoTokioAsStd; + type Timer = TokioTime; + type Udp = ShadowUdpSocket; + + fn create_handle(&self) -> Self::Handle { + self.handle.clone() + } + + fn connect_tcp(&self, server_addr: SocketAddr) -> Pin>>> { + let connect_opts = self.connect_opts.clone(); + Box::pin(async move { + let tcp = ShadowTcpStream::connect_with_opts(&server_addr, &connect_opts).await?; + Ok(AsyncIoTokioAsStd(tcp)) + }) + } + + fn bind_udp( + &self, + local_addr: SocketAddr, + _server_addr: SocketAddr, + ) -> Pin>>> { + let connect_opts = self.connect_opts.clone(); + Box::pin(async move { + let udp = ShadowUdpSocket::bind_with_opts(&local_addr, &connect_opts).await?; + Ok(udp) + }) + } +} + +/// Shadowsocks DNS resolver +/// +/// A customized trust-dns-resolver +pub type DnsResolver = AsyncResolver; + /// Create a `trust-dns` asynchronous DNS resolver -pub async fn create_resolver(dns: Option, _ipv6_first: bool) -> ResolveResult { +pub async fn create_resolver(dns: Option, connect_opts: ConnectOpts) -> ResolveResult { // Customized dns resolution match dns { Some(conf) => { @@ -23,7 +110,7 @@ pub async fn create_resolver(dns: Option, _ipv6_first: bool) -> conf, resolver_opts ); - TokioAsyncResolver::tokio(conf, resolver_opts) + DnsResolver::new(conf, resolver_opts, ShadowDnsProvider::new(connect_opts)) } // To make this independent, if targeting macOS, BSD, Linux, or Windows, we can use the system's configuration @@ -31,7 +118,7 @@ pub async fn create_resolver(dns: Option, _ipv6_first: bool) -> None => { cfg_if! { if #[cfg(any(all(unix, not(target_os = "android")), windows))] { - use trust_dns_resolver::{name_server::TokioHandle, system_conf::read_system_conf}; + use trust_dns_resolver::system_conf::read_system_conf; // use the system resolver configuration let (config, mut opts) = match read_system_conf() { @@ -58,7 +145,7 @@ pub async fn create_resolver(dns: Option, _ipv6_first: bool) -> opts ); - TokioAsyncResolver::new(config, opts, TokioHandle) + DnsResolver::new(config, opts, ShadowDnsProvider::new(connect_opts)) } else { use trust_dns_resolver::error::ResolveError; diff --git a/crates/shadowsocks/src/net/sys/unix/bsd/freebsd.rs b/crates/shadowsocks/src/net/sys/unix/bsd/freebsd.rs index 7a7651a60452..56bec3f7eb22 100644 --- a/crates/shadowsocks/src/net/sys/unix/bsd/freebsd.rs +++ b/crates/shadowsocks/src/net/sys/unix/bsd/freebsd.rs @@ -226,8 +226,8 @@ pub fn set_disable_ip_fragmentation(af: AddrFamily, socket: &S) -> i Ok(()) } -/// Create a `UdpSocket` for connecting to `addr` -#[inline(always)] +/// Create a `UdpSocket` with specific address family +#[inline] pub async fn create_outbound_udp_socket(af: AddrFamily, config: &ConnectOpts) -> io::Result { let bind_addr = match (af, config.bind_local_addr) { (AddrFamily::Ipv4, Some(IpAddr::V4(ip))) => SocketAddr::new(ip.into(), 0), @@ -236,11 +236,18 @@ pub async fn create_outbound_udp_socket(af: AddrFamily, config: &ConnectOpts) -> (AddrFamily::Ipv6, ..) => SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0), }; + bind_outbound_udp_socket(&bind_addr, config).await +} + +/// Create a `UdpSocket` binded to `bind_addr` +pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, _config: &ConnectOpts) -> io::Result { + let af = AddrFamily::from(bind_addr); + let socket = if af != AddrFamily::Ipv6 { UdpSocket::bind(bind_addr).await? } else { - let socket = Socket::new(Domain::for_address(bind_addr), Type::DGRAM, Some(Protocol::UDP))?; - socket_bind_dual_stack(&socket, &bind_addr, false)?; + let socket = Socket::new(Domain::for_address(*bind_addr), Type::DGRAM, Some(Protocol::UDP))?; + socket_bind_dual_stack(&socket, bind_addr, false)?; // UdpSocket::from_std requires socket to be non-blocked socket.set_nonblocking(true)?; diff --git a/crates/shadowsocks/src/net/sys/unix/bsd/macos.rs b/crates/shadowsocks/src/net/sys/unix/bsd/macos.rs index e90e1547d8e5..fe2d94dc4d5f 100644 --- a/crates/shadowsocks/src/net/sys/unix/bsd/macos.rs +++ b/crates/shadowsocks/src/net/sys/unix/bsd/macos.rs @@ -65,7 +65,7 @@ impl TcpStream { async fn connect_with_socket(socket: TcpSocket, addr: SocketAddr, opts: &ConnectOpts) -> io::Result { // Binds to a specific network interface (device) if let Some(ref iface) = opts.bind_interface { - set_ip_bound_if(&socket, addr, iface)?; + set_ip_bound_if(&socket, &addr, iface)?; } set_common_sockopt_for_connect(addr, &socket, opts)?; @@ -230,7 +230,7 @@ pub async fn create_inbound_tcp_socket(bind_addr: &SocketAddr, _accept_opts: &Ac } } -fn set_ip_bound_if(socket: &S, addr: SocketAddr, iface: &str) -> io::Result<()> { +fn set_ip_bound_if(socket: &S, addr: &SocketAddr, iface: &str) -> io::Result<()> { const IP_BOUND_IF: libc::c_int = 25; // bsd/netinet/in.h const IPV6_BOUND_IF: libc::c_int = 125; // bsd/netinet6/in6.h @@ -319,7 +319,8 @@ pub fn set_disable_ip_fragmentation(af: AddrFamily, socket: &S) -> i Ok(()) } -/// Create a `UdpSocket` for connecting to `addr` +/// Create a `UdpSocket` with specific address family +#[inline] pub async fn create_outbound_udp_socket(af: AddrFamily, config: &ConnectOpts) -> io::Result { let bind_addr = match (af, config.bind_local_addr) { (AddrFamily::Ipv4, Some(IpAddr::V4(ip))) => SocketAddr::new(ip.into(), 0), @@ -328,10 +329,17 @@ pub async fn create_outbound_udp_socket(af: AddrFamily, config: &ConnectOpts) -> (AddrFamily::Ipv6, ..) => SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0), }; + bind_outbound_udp_socket(&bind_addr, config).await +} + +/// Create a `UdpSocket` binded to `bind_addr` +pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, config: &ConnectOpts) -> io::Result { + let af = AddrFamily::from(bind_addr); + let socket = if af != AddrFamily::Ipv6 { UdpSocket::bind(bind_addr).await? } else { - let socket = Socket::new(Domain::for_address(bind_addr), Type::DGRAM, Some(Protocol::UDP))?; + let socket = Socket::new(Domain::for_address(*bind_addr), Type::DGRAM, Some(Protocol::UDP))?; socket_bind_dual_stack(&socket, &bind_addr, false)?; // UdpSocket::from_std requires socket to be non-blocked diff --git a/crates/shadowsocks/src/net/sys/unix/linux/mod.rs b/crates/shadowsocks/src/net/sys/unix/linux/mod.rs index 38261f6b6d9d..737c8363d39a 100644 --- a/crates/shadowsocks/src/net/sys/unix/linux/mod.rs +++ b/crates/shadowsocks/src/net/sys/unix/linux/mod.rs @@ -279,7 +279,8 @@ pub fn set_disable_ip_fragmentation(af: AddrFamily, socket: &S) -> i Ok(()) } -/// Create a `UdpSocket` for connecting to `addr` +/// Create a `UdpSocket` with specific address family +#[inline] pub async fn create_outbound_udp_socket(af: AddrFamily, config: &ConnectOpts) -> io::Result { let bind_addr = match (af, config.bind_local_addr) { (AddrFamily::Ipv4, Some(IpAddr::V4(ip))) => SocketAddr::new(ip.into(), 0), @@ -288,11 +289,18 @@ pub async fn create_outbound_udp_socket(af: AddrFamily, config: &ConnectOpts) -> (AddrFamily::Ipv6, ..) => SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0), }; + bind_outbound_udp_socket(&bind_addr, config).await +} + +/// Create a `UdpSocket` binded to `bind_addr` +pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, config: &ConnectOpts) -> io::Result { + let af = AddrFamily::from(bind_addr); + let socket = if af != AddrFamily::Ipv6 { UdpSocket::bind(bind_addr).await? } else { - let socket = Socket::new(Domain::for_address(bind_addr), Type::DGRAM, Some(Protocol::UDP))?; - socket_bind_dual_stack(&socket, &bind_addr, false)?; + let socket = Socket::new(Domain::for_address(*bind_addr), Type::DGRAM, Some(Protocol::UDP))?; + socket_bind_dual_stack(&socket, bind_addr, false)?; // UdpSocket::from_std requires socket to be non-blocked socket.set_nonblocking(true)?; diff --git a/crates/shadowsocks/src/net/sys/unix/others.rs b/crates/shadowsocks/src/net/sys/unix/others.rs index 8caeabc38f69..04251c57bd87 100644 --- a/crates/shadowsocks/src/net/sys/unix/others.rs +++ b/crates/shadowsocks/src/net/sys/unix/others.rs @@ -78,8 +78,8 @@ pub fn set_disable_ip_fragmentation(_af: AddrFamily, _socket: &S) -> Ok(()) } -/// Create a `UdpSocket` for connecting to `addr` -#[inline(always)] +/// Create a `UdpSocket` with specific address family +#[inline] pub async fn create_outbound_udp_socket(af: AddrFamily, config: &ConnectOpts) -> io::Result { let bind_addr = match (af, config.bind_local_addr) { (AddrFamily::Ipv4, Some(IpAddr::V4(ip))) => SocketAddr::new(ip.into(), 0), @@ -88,6 +88,13 @@ pub async fn create_outbound_udp_socket(af: AddrFamily, config: &ConnectOpts) -> (AddrFamily::Ipv6, ..) => SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0), }; + bind_outbound_udp_socket(&bind_addr, config).await +} + +/// Create a `UdpSocket` binded to `bind_addr` +pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, _config: &ConnectOpts) -> io::Result { + let af = AddrFamily::from(bind_addr); + let socket = UdpSocket::bind(bind_addr).await?; let _ = set_disable_ip_fragmentation(af, &socket); diff --git a/crates/shadowsocks/src/net/sys/windows/mod.rs b/crates/shadowsocks/src/net/sys/windows/mod.rs index c9ed3f76af7a..19c11ad813f3 100644 --- a/crates/shadowsocks/src/net/sys/windows/mod.rs +++ b/crates/shadowsocks/src/net/sys/windows/mod.rs @@ -23,8 +23,20 @@ use windows_sys::{ Foundation::BOOL, NetworkManagement::IpHelper::if_nametoindex, Networking::WinSock::{ - setsockopt, WSAGetLastError, WSAIoctl, IPPROTO_IP, IPPROTO_IPV6, IPPROTO_TCP, IPV6_MTU_DISCOVER, - IPV6_UNICAST_IF, IP_MTU_DISCOVER, IP_PMTUDISC_DO, IP_UNICAST_IF, SIO_UDP_CONNRESET, SOCKET, SOCKET_ERROR, + setsockopt, + WSAGetLastError, + WSAIoctl, + IPPROTO_IP, + IPPROTO_IPV6, + IPPROTO_TCP, + IPV6_MTU_DISCOVER, + IPV6_UNICAST_IF, + IP_MTU_DISCOVER, + IP_PMTUDISC_DO, + IP_UNICAST_IF, + SIO_UDP_CONNRESET, + SOCKET, + SOCKET_ERROR, TCP_FASTOPEN, }, }, @@ -36,7 +48,9 @@ const FALSE: BOOL = 0; use crate::net::{ is_dual_stack_addr, sys::{set_common_sockopt_for_connect, socket_bind_dual_stack}, - AcceptOpts, AddrFamily, ConnectOpts, + AcceptOpts, + AddrFamily, + ConnectOpts, }; /// A `TcpStream` that supports TFO (TCP Fast Open) @@ -55,7 +69,7 @@ impl TcpStream { // Binds to a specific network interface (device) if let Some(ref iface) = opts.bind_interface { - set_ip_unicast_if(&socket, addr, iface)?; + set_ip_unicast_if(&socket, &addr, iface)?; } set_common_sockopt_for_connect(addr, &socket, opts)?; @@ -183,7 +197,7 @@ pub async fn create_inbound_tcp_socket(bind_addr: &SocketAddr, _accept_opts: &Ac } } -fn set_ip_unicast_if(socket: &S, addr: SocketAddr, iface: &str) -> io::Result<()> { +fn set_ip_unicast_if(socket: &S, addr: &SocketAddr, iface: &str) -> io::Result<()> { let handle = socket.as_raw_socket() as SOCKET; unsafe { @@ -348,10 +362,17 @@ pub async fn create_outbound_udp_socket(af: AddrFamily, opts: &ConnectOpts) -> i (AddrFamily::Ipv6, ..) => SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0), }; + bind_outbound_udp_socket(&bind_addr, opts).await +} + +/// Create a `UdpSocket` binded to `bind_addr` +pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, opts: &ConnectOpts) -> io::Result { + let af = AddrFamily::from(bind_addr); + let socket = if af != AddrFamily::Ipv6 { UdpSocket::bind(bind_addr).await? } else { - let socket = Socket::new(Domain::for_address(bind_addr), Type::DGRAM, Some(Protocol::UDP))?; + let socket = Socket::new(Domain::for_address(*bind_addr), Type::DGRAM, Some(Protocol::UDP))?; socket_bind_dual_stack(&socket, &bind_addr, false)?; // UdpSocket::from_std requires socket to be non-blocked diff --git a/crates/shadowsocks/src/net/udp.rs b/crates/shadowsocks/src/net/udp.rs index e7e4a64c2216..14077c9df7f0 100644 --- a/crates/shadowsocks/src/net/udp.rs +++ b/crates/shadowsocks/src/net/udp.rs @@ -35,7 +35,7 @@ use tokio::io::Interest; use crate::{context::Context, relay::socks5::Address, ServerAddr}; use super::{ - sys::{create_inbound_udp_socket, create_outbound_udp_socket}, + sys::{bind_outbound_udp_socket, create_inbound_udp_socket, create_outbound_udp_socket}, AcceptOpts, AddrFamily, ConnectOpts, @@ -127,6 +127,16 @@ impl UdpSocket { Ok(UdpSocket(socket)) } + /// Binds to a specific address with opts + pub async fn connect_any_with_opts>(af: AF, opts: &ConnectOpts) -> io::Result { + create_outbound_udp_socket(af.into(), opts).await.map(UdpSocket) + } + + /// Binds to a specific address with opts as an outbound socket + pub async fn bind_with_opts(addr: &SocketAddr, opts: &ConnectOpts) -> io::Result { + bind_outbound_udp_socket(addr, opts).await.map(UdpSocket) + } + /// Binds to a specific address (inbound) #[inline] pub async fn listen(addr: &SocketAddr) -> io::Result { @@ -139,11 +149,6 @@ impl UdpSocket { Ok(UdpSocket(socket)) } - /// Binds to a specific address with opts - pub async fn connect_any_with_opts>(af: AF, opts: &ConnectOpts) -> io::Result { - create_outbound_udp_socket(af.into(), opts).await.map(UdpSocket) - } - /// Batch send packets #[cfg(any( target_os = "linux", diff --git a/src/service/local.rs b/src/service/local.rs index d260f87cce60..6e40d00f9a14 100644 --- a/src/service/local.rs +++ b/src/service/local.rs @@ -183,7 +183,7 @@ pub fn define_command_line_options(mut app: Command) -> Command { .help("Set SIP003 plugin options"), ) .arg( - Arg::new("URL") + Arg::new("SERVER_URL") .long("server-url") .num_args(1) .action(ArgAction::Set) @@ -192,7 +192,7 @@ pub fn define_command_line_options(mut app: Command) -> Command { .help("Server address in SIP002 (https://shadowsocks.org/guide/sip002.html) URL"), ) .group(ArgGroup::new("SERVER_CONFIG") - .arg("SERVER_ADDR").arg("URL").multiple(true)) + .arg("SERVER_ADDR").arg("SERVER_URL").multiple(true)) .arg( Arg::new("ACL") .long("acl") @@ -591,7 +591,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode { config.server.push(ServerInstanceConfig::with_server_config(sc)); } - if let Some(svr_addr) = matches.get_one::("URL").cloned() { + if let Some(svr_addr) = matches.get_one::("SERVER_URL").cloned() { config.server.push(ServerInstanceConfig::with_server_config(svr_addr)); }