├── .gitignore ├── res ├── dnsd.png └── dnsd_win.png ├── Cargo.toml ├── README.md ├── Cargo.lock └── src └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /res/dnsd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-net/dnsd/HEAD/res/dnsd.png -------------------------------------------------------------------------------- /res/dnsd_win.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-net/dnsd/HEAD/res/dnsd_win.png -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dnsd" 3 | version = "0.1.0" 4 | authors = ["develon "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | tokio = { version = "1.5.0", features = ["full"] } # An event-driven, non-blocking I/O platform for writing asynchronous I/O backed applications. 11 | ttycolor = "0.1.0" # easy way to use termcolor 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dnsd 2 | 3 | DNS 污染是一种让一般用户由于得到虚假目标主机IP而不能与其通信的方法,是一种 DNS 缓存投毒攻击(DNS cache poisoning)。其工作方式是:由于通常的 DNS 查询没有任何认证机制,而且 DNS 查询通常基于无连接不可靠的 UDP 协议,因此 DNS 的查询非常容易被篡改,通过对 UDP 数据传输进行侦听,筛选 DNS 查询,一经发现黑名单上的 DNS 请求则立即伪装成目标域名的解析服务器(NS,Name Server)给查询者返回虚假结果,同时也会篡改服务器发送的 DNS 响应。 4 | 5 | dnsd 使用 TCP 传输协议代理 DNS 请求,可提高 DNS 污染的成本,获得相对真实的 DNS 响应。但由于明文传输,TCP 请求仍有可能被重置、中断。如果您没有 TCP 全局代理的解决方案,那么可以尝试在相对安全的网络服务器上搭建一个加密的 DNS 服务,尝试使用 [client-server](https://github.com/develon2015/dnsd/tree/client-server) 架构。 6 | 7 | 8 | ## Usage 9 | ``` 10 | ./dnsd 127.0.0.1:53 1.1.1.1:53 log_on 11 | ``` 12 | 13 | ![./res/dsnds.png](https://raw.githubusercontent.com/develon2015/dnsd/rust/res/dnsd_win.png) 14 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "autocfg" 5 | version = "1.0.1" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 8 | 9 | [[package]] 10 | name = "bitflags" 11 | version = "1.2.1" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 14 | 15 | [[package]] 16 | name = "bytes" 17 | version = "1.0.1" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" 20 | 21 | [[package]] 22 | name = "cfg-if" 23 | version = "1.0.0" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 26 | 27 | [[package]] 28 | name = "dnsd" 29 | version = "0.1.0" 30 | dependencies = [ 31 | "tokio", 32 | "ttycolor", 33 | ] 34 | 35 | [[package]] 36 | name = "hermit-abi" 37 | version = "0.1.18" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" 40 | dependencies = [ 41 | "libc", 42 | ] 43 | 44 | [[package]] 45 | name = "instant" 46 | version = "0.1.9" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" 49 | dependencies = [ 50 | "cfg-if", 51 | ] 52 | 53 | [[package]] 54 | name = "libc" 55 | version = "0.2.93" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" 58 | 59 | [[package]] 60 | name = "lock_api" 61 | version = "0.4.3" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" 64 | dependencies = [ 65 | "scopeguard", 66 | ] 67 | 68 | [[package]] 69 | name = "log" 70 | version = "0.4.14" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 73 | dependencies = [ 74 | "cfg-if", 75 | ] 76 | 77 | [[package]] 78 | name = "memchr" 79 | version = "2.3.4" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" 82 | 83 | [[package]] 84 | name = "mio" 85 | version = "0.7.11" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956" 88 | dependencies = [ 89 | "libc", 90 | "log", 91 | "miow", 92 | "ntapi", 93 | "winapi", 94 | ] 95 | 96 | [[package]] 97 | name = "miow" 98 | version = "0.3.7" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 101 | dependencies = [ 102 | "winapi", 103 | ] 104 | 105 | [[package]] 106 | name = "ntapi" 107 | version = "0.3.6" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 110 | dependencies = [ 111 | "winapi", 112 | ] 113 | 114 | [[package]] 115 | name = "num_cpus" 116 | version = "1.13.0" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 119 | dependencies = [ 120 | "hermit-abi", 121 | "libc", 122 | ] 123 | 124 | [[package]] 125 | name = "once_cell" 126 | version = "1.7.2" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" 129 | 130 | [[package]] 131 | name = "parking_lot" 132 | version = "0.11.1" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" 135 | dependencies = [ 136 | "instant", 137 | "lock_api", 138 | "parking_lot_core", 139 | ] 140 | 141 | [[package]] 142 | name = "parking_lot_core" 143 | version = "0.8.3" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" 146 | dependencies = [ 147 | "cfg-if", 148 | "instant", 149 | "libc", 150 | "redox_syscall", 151 | "smallvec", 152 | "winapi", 153 | ] 154 | 155 | [[package]] 156 | name = "pin-project-lite" 157 | version = "0.2.6" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" 160 | 161 | [[package]] 162 | name = "proc-macro2" 163 | version = "1.0.26" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" 166 | dependencies = [ 167 | "unicode-xid", 168 | ] 169 | 170 | [[package]] 171 | name = "quote" 172 | version = "1.0.9" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 175 | dependencies = [ 176 | "proc-macro2", 177 | ] 178 | 179 | [[package]] 180 | name = "redox_syscall" 181 | version = "0.2.6" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "8270314b5ccceb518e7e578952f0b72b88222d02e8f77f5ecf7abbb673539041" 184 | dependencies = [ 185 | "bitflags", 186 | ] 187 | 188 | [[package]] 189 | name = "scopeguard" 190 | version = "1.1.0" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 193 | 194 | [[package]] 195 | name = "signal-hook-registry" 196 | version = "1.3.0" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" 199 | dependencies = [ 200 | "libc", 201 | ] 202 | 203 | [[package]] 204 | name = "smallvec" 205 | version = "1.6.1" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" 208 | 209 | [[package]] 210 | name = "syn" 211 | version = "1.0.70" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883" 214 | dependencies = [ 215 | "proc-macro2", 216 | "quote", 217 | "unicode-xid", 218 | ] 219 | 220 | [[package]] 221 | name = "termcolor" 222 | version = "1.1.2" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 225 | dependencies = [ 226 | "winapi-util", 227 | ] 228 | 229 | [[package]] 230 | name = "tokio" 231 | version = "1.5.0" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "83f0c8e7c0addab50b663055baf787d0af7f413a46e6e7fb9559a4e4db7137a5" 234 | dependencies = [ 235 | "autocfg", 236 | "bytes", 237 | "libc", 238 | "memchr", 239 | "mio", 240 | "num_cpus", 241 | "once_cell", 242 | "parking_lot", 243 | "pin-project-lite", 244 | "signal-hook-registry", 245 | "tokio-macros", 246 | "winapi", 247 | ] 248 | 249 | [[package]] 250 | name = "tokio-macros" 251 | version = "1.1.0" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57" 254 | dependencies = [ 255 | "proc-macro2", 256 | "quote", 257 | "syn", 258 | ] 259 | 260 | [[package]] 261 | name = "ttycolor" 262 | version = "0.1.0" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "c9fae6447ca6172ccd0b4adbc83c84a5b8dae5afe3fff233c4fdc28fcba54de4" 265 | dependencies = [ 266 | "termcolor", 267 | ] 268 | 269 | [[package]] 270 | name = "unicode-xid" 271 | version = "0.2.1" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 274 | 275 | [[package]] 276 | name = "winapi" 277 | version = "0.3.9" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 280 | dependencies = [ 281 | "winapi-i686-pc-windows-gnu", 282 | "winapi-x86_64-pc-windows-gnu", 283 | ] 284 | 285 | [[package]] 286 | name = "winapi-i686-pc-windows-gnu" 287 | version = "0.4.0" 288 | source = "registry+https://github.com/rust-lang/crates.io-index" 289 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 290 | 291 | [[package]] 292 | name = "winapi-util" 293 | version = "0.1.5" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 296 | dependencies = [ 297 | "winapi", 298 | ] 299 | 300 | [[package]] 301 | name = "winapi-x86_64-pc-windows-gnu" 302 | version = "0.4.0" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 305 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use tokio::io::AsyncReadExt; 4 | use tokio::io::AsyncWriteExt; 5 | use tokio::net::UdpSocket; 6 | 7 | extern crate ttycolor; 8 | use ttycolor::*; 9 | 10 | const DEBUG: bool = false; 11 | 12 | const LISTEN: &str = "127.0.0.1:53"; 13 | const SERVER: &str = "1.1.1.1:53"; 14 | // const SERVER: &str = "114.114.114.114:53"; 15 | 16 | struct DNS<'a> { 17 | value: &'a [u8], 18 | offset: usize, 19 | } 20 | impl<'a> DNS<'a> { 21 | pub fn with(value: &'a [u8], offset: usize) -> Self { 22 | return Self { value, offset }; 23 | } 24 | pub fn to_string(&self) -> String { 25 | let mut str = String::with_capacity(1024); 26 | for a in &self.value[self.offset..] { 27 | // str.push_str(format!("{:08b} ", a).as_str()); 28 | str.push_str(format!("{:02x} ", a).as_str()); 29 | } 30 | str.pop(); 31 | str 32 | } 33 | pub fn id(&self) -> u16 { 34 | self.value[self.offset + 0] as u16 * 256 + self.value[self.offset + 1] as u16 35 | } 36 | pub fn qr(&self) -> &'static str { 37 | let qr: u8 = self.value[self.offset + 2] >> 7; 38 | if qr == 0 { 39 | "request" 40 | } else { 41 | "response" 42 | } 43 | } 44 | pub fn opcode(&self) -> &'static str { 45 | let opcode: u8 = (self.value[self.offset + 2] & 0b_0_1111_000) >> 3; 46 | match opcode { 47 | 0 => "标准查询", 48 | 1 => "反转查询", 49 | 2 => "状态查询", 50 | _ => "保留", 51 | } 52 | } 53 | pub fn rcode(&self) -> &'static str { 54 | let opcode: u8 = self.value[self.offset + 3] & 0b_0000_1111; 55 | match opcode { 56 | 0 => "没有错误", 57 | 1 => "请求格式有误,服务器无法解析请求", 58 | 2 => "服务器出错", 59 | 3 => "请求中的域名不存在", 60 | 4 => "服务器不支持该请求类型", 61 | 5 => "服务器拒绝执行请求操作", 62 | _ => "保留", 63 | } 64 | } 65 | pub fn qdcount(&self) -> u16 { 66 | let count: u16 = 67 | self.value[self.offset + 4] as u16 * 256 + self.value[self.offset + 5] as u16; 68 | count 69 | } 70 | pub fn ancount(&self) -> u16 { 71 | let count: u16 = 72 | self.value[self.offset + 6] as u16 * 256 + self.value[self.offset + 7] as u16; 73 | count 74 | } 75 | pub fn nscount(&self) -> u16 { 76 | let count: u16 = 77 | self.value[self.offset + 8] as u16 * 256 + self.value[self.offset + 9] as u16; 78 | count 79 | } 80 | pub fn arcount(&self) -> u16 { 81 | let count: u16 = 82 | self.value[self.offset + 10] as u16 * 256 + self.value[self.offset + 11] as u16; 83 | count 84 | } 85 | pub fn question_list(&self) -> Vec<(String, &'static str)> { 86 | let mut vec = Vec::with_capacity(1); 87 | let mut j = 12; 88 | for _ in 0..self.qdcount() { 89 | let mut str = String::with_capacity(1024); 90 | loop { 91 | let ch = self.value[self.offset + j]; 92 | j += 1; 93 | for k in 0..ch { 94 | let nch = self.value[self.offset + j + k as usize] as char; 95 | str.push(nch); 96 | } 97 | j += ch as usize; 98 | if self.value[self.offset + j] == 0 { 99 | break; 100 | } 101 | str.push('.'); 102 | } 103 | let qtype: u16 = self.value[self.offset + j + 1] as u16 * 256 104 | + self.value[self.offset + j + 2] as u16; 105 | vec.push(( 106 | str, 107 | match qtype { 108 | 1 => "A", 109 | 0x1c => "AAAA", 110 | 2 => "NS", 111 | 3 => "MD", 112 | 4 => "MF", 113 | 5 => "CNAME", 114 | 15 => "MX", 115 | 16 => "TXT", 116 | _ => "_", 117 | }, 118 | )); 119 | j += 4; // QTYPE 2 bytes and QCLASS 2 bytes 120 | } 121 | vec 122 | } 123 | pub fn question(&self) -> String { 124 | let mut str = String::with_capacity(1024); 125 | str.push_str("{ "); 126 | for question in self.question_list() { 127 | str.push_str(&format!("{name} ({type}) ", name = question.0, type = question.1)); 128 | } 129 | str.push_str("}"); 130 | str 131 | } 132 | pub fn answer_list(&self) -> Vec { 133 | let mut vec = Vec::with_capacity(2); 134 | // 从何处寻找answer 135 | let mut n = self.offset + 12; // offset + Header 136 | for _ in 0..self.qdcount() { 137 | loop { 138 | if self.value[n] == 0 { 139 | n += 1 + 4; // 4 is QTYPE and QCLASS 140 | break; 141 | } 142 | n += 1; 143 | } 144 | } 145 | 146 | fn b2a(b: &[u8]) -> String { 147 | match b.len() { 148 | 4 => format!("{}.{}.{}.{}", b[0], b[1], b[2], b[3]), 149 | 16 => { 150 | let mut str = String::with_capacity(40); 151 | for i in 0..b.len() { 152 | str.push_str(&format!("{:02x}", b[i])); 153 | if i % 2 == 1 { 154 | str.push(':'); 155 | } 156 | } 157 | str.pop(); 158 | str.replace("0000", "").replace("::", ":") 159 | }, 160 | _ => format!("{:02x?}", b), 161 | } 162 | } 163 | 164 | // 长度不定,可能是真正的数据,也有可能是指针(其值表示的是真正的数据在整个数据中的字节索引数),还有可能是二者的混合(以指针结尾)。 165 | // 若是真正的数据,会以0x00结尾;若是指针,指针占2个字节,第一个字节的高2位为11。 166 | for _ in 0..self.ancount() { 167 | if self.value[n] & 0b_1100_0000 == 0b_1100_0000 { 168 | let qtype = self.value[n + 2] as u16 * 256 + self.value[n + 3] as u16; 169 | match qtype { 170 | 0x0001 | 0x001c => { 171 | let pointer = 172 | (self.value[n] & 0b_0011_1111) as u16 * 256 + self.value[n + 1] as u16; 173 | let rdlength = self.value[n + pointer as usize - 2] as u16 * 256 174 | + self.value[n + pointer as usize - 1] as u16; // RDLENGTH 175 | vec.push(b2a( 176 | &self.value[n + pointer as usize..n + pointer as usize + rdlength as usize] 177 | )); 178 | n += (pointer + rdlength) as usize; 179 | }, 180 | 0x0005 => { 181 | vec.push("CNAME".to_string()); 182 | break; 183 | }, 184 | _ => { 185 | vec.push("Unknown QTYPE".to_string()); 186 | break; 187 | }, 188 | } 189 | } else { // not pointer 190 | vec.push("Not Pointer".to_string()); 191 | break; 192 | } 193 | } 194 | vec 195 | } 196 | pub fn answer(&self) -> String { 197 | if self.ancount() == 0 { 198 | return format!("Authority: {}, Additional: {}", self.nscount(), self.arcount()); 199 | } 200 | let mut str = String::with_capacity(1024); 201 | for answer in self.answer_list() { 202 | str.push_str(&format!("{}, ", answer)); 203 | } 204 | str.pop(); 205 | str.pop(); 206 | str 207 | } 208 | pub fn info(&self) { 209 | // let target = self.question_list(); 210 | // let target = target.get(0).unwrap(); 211 | // if target.0 != "y2b.123345.xyz" { // test case 212 | // return; 213 | // } 214 | if self.qr() == "request" { 215 | println!( 216 | "{id} {opcode} {question}", 217 | opcode = self.opcode(), 218 | id = self.id(), 219 | question = self.question().magenta().bold(), 220 | ); 221 | } else { 222 | println!( 223 | "{id} {opcode} {question} ({rcode})", 224 | rcode = self.rcode().green(), 225 | opcode = self.opcode(), 226 | id = self.id(), 227 | question = self.question().magenta().bold(), 228 | ); 229 | println!( 230 | " | {answer} |", 231 | answer = self.answer().red().bold(), 232 | ); 233 | } 234 | // println!("{:02x?}", self.value); // 以十六进制而非十进制打印数组 235 | println!("{}", self.to_string().bg_white().black()); 236 | println!( 237 | "-----------------------------------------------------------------------------------" 238 | ); 239 | } 240 | } 241 | #[test] 242 | fn test() { 243 | DNS::with( 244 | &[ 245 | 0u8, 0, 245, 178, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 6, 103, 111, 111, 103, 108, 101, 3, 99, 246 | 111, 109, 0, 0, 1, 0, 1, 247 | ], 248 | 2, 249 | ) 250 | .info(); 251 | DNS::with( 252 | &[ 253 | 0u8, 44, 245, 178, 129, 128, 0, 1, 0, 1, 0, 0, 0, 0, 6, 103, 111, 111, 103, 108, 101, 254 | 3, 99, 111, 109, 0, 0, 1, 0, 1, 192, 12, 0, 1, 0, 1, 0, 0, 0, 176, 0, 4, 142, 0, 176, 255 | 0, 4, 142, 250, 72, 174, 256 | ], 257 | 2, 258 | ) 259 | .info(); 260 | } 261 | 262 | async fn udp_serv() -> std::io::Result<()> { 263 | let server = std::env::args().nth(2).unwrap_or(SERVER.to_string()); 264 | let listen= std::env::args().nth(1).unwrap_or(LISTEN.to_string()); 265 | let log = std::env::args().nth(3).unwrap_or("on".to_string()); 266 | let log = DEBUG || if let Some(_) = ["log_off", "off", "close"].iter().find(|&&it| (it == log.as_str())) { false } else { true }; 267 | let listener = tokio::net::UdpSocket::bind(&listen).await; 268 | if let Err(e) = listener { 269 | println!("无法启用监听服务: {}", e); 270 | return Err(e); 271 | } 272 | let listener: UdpSocket = listener.ok().unwrap(); 273 | let listener = std::sync::Arc::new(listener); 274 | println!("{}: {} -> {}", "DNS代理服务已启动".red().bold(), listen.cyan().bold(), server.green().bold()); 275 | println!("{}", if log { "日志已开启" } else { "日志已关闭" }.red()); 276 | println!( 277 | "-----------------------------------------------------------------------------------" 278 | ); 279 | 280 | let map: HashMap<_, _> = HashMap::, Vec>::with_capacity(1024); // cache 281 | let map: tokio::sync::Mutex<_> = tokio::sync::Mutex::new(map); // Mutex 282 | let map: std::sync::Arc<_> = std::sync::Arc::new(map); // Arc> 283 | 284 | let mut query = [0u8; 1024]; // DNS query request data 285 | loop { 286 | let server = server.clone(); 287 | let listener = listener.clone(); 288 | let recv_result = listener.recv_from(&mut query[2..]).await; 289 | if let Err(_) = recv_result { 290 | continue; 291 | } 292 | let (received, client) = recv_result.ok().unwrap(); 293 | if log { 294 | println!("{}", "==>> DNS查询 ==>>".cyan().bold()); 295 | DNS::with(&query[..received + 2], 2).info(); 296 | } 297 | 298 | let map1 = map.clone(); 299 | let map2 = map.clone(); 300 | // Find cache 301 | let cache = map1.lock().await; 302 | let cache = cache.get(&query[4..received + 2]); 303 | if let Some(cache) = cache { 304 | let mut buf = vec![0u8; 2 + cache.len()]; 305 | buf[0] = query[2]; // ID 306 | buf[1] = query[3]; 307 | &buf[2..2 + cache.len()].copy_from_slice(&cache[..]); 308 | if log { 309 | println!("{}", " <<== 已缓存 <<==".blue().bold()); 310 | print!(" "); 311 | DNS::with(&buf[..cache.len() + 2], 0).info(); 312 | } 313 | if let Err(e) = listener.send_to(&buf, client).await { 314 | eprintln!("Error: {}", e); 315 | } 316 | continue; 317 | } 318 | 319 | tokio::spawn(async move { 320 | // TCP data body length 321 | query[0] = (received / 0xff) as u8; 322 | query[1] = (received % 0xff) as u8; 323 | 324 | // Connect server 325 | let tcp = tokio::net::TcpStream::connect(&server).await; 326 | if let Err(e) = tcp { 327 | println!("{}", format!("无法连接服务器{}:{}", server, e).red()); 328 | return; 329 | } 330 | let mut tcp = tcp.ok().unwrap(); 331 | 332 | // Faword query request 333 | let writed = tcp.write(&query[..received + 2]).await; 334 | if let Err(e) = writed { 335 | println!("{}", format!("意外的错误:{}", e).red()); 336 | return; 337 | } 338 | 339 | let mut resp = [0u8; 2048]; 340 | if let Ok(le) = tcp.read(&mut resp).await { 341 | let mut map = map2.lock().await; 342 | map.insert(Vec::from(&query[4..received + 2]), Vec::from(&resp[4..le])); 343 | listener.send_to(&resp[2..le], client).await.unwrap(); 344 | if log { 345 | println!("{}", " <<== DNS响应 <<==".green().bold()); 346 | print!(" "); 347 | DNS::with(&resp[..le], 2).info(); 348 | } 349 | } 350 | }); 351 | } 352 | } 353 | 354 | #[tokio::main] 355 | async fn main() -> std::io::Result<()> { 356 | udp_serv().await 357 | } 358 | --------------------------------------------------------------------------------