diff --git a/Cargo.lock b/Cargo.lock index f94ce0d0..62319970 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1002,7 +1002,6 @@ dependencies = [ "hickory-client", "hickory-proto 0.25.0-alpha.2", "hickory-resolver 0.25.0-alpha.2", - "hickory-server", "hmac", "http", "http-body-util", @@ -1070,6 +1069,7 @@ dependencies = [ "unix-udp-sock", "url", "uuid", + "watfaq-dns", "webpki-roots", "windows 0.58.0", ] @@ -6884,6 +6884,27 @@ version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +[[package]] +name = "watfaq-dns" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e4caff90e06dd6f6fdcefbce28fe42ce7d9ab7741639d0db49dca897defe405" +dependencies = [ + "async-trait", + "futures", + "hickory-client", + "hickory-proto 0.25.0-alpha.2", + "hickory-resolver 0.25.0-alpha.2", + "hickory-server", + "rustls", + "rustls-pemfile", + "serde", + "thiserror", + "tokio", + "tracing", + "webpki-roots", +] + [[package]] name = "weak-table" version = "0.3.2" diff --git a/clash_lib/Cargo.toml b/clash_lib/Cargo.toml index 6f1f5a5a..0701d90a 100644 --- a/clash_lib/Cargo.toml +++ b/clash_lib/Cargo.toml @@ -98,9 +98,9 @@ serde_json = "1" erased-serde = "0.4" # DNS +watfaq-dns = { version = "0.1" } hickory-client = "0.25.0-alpha.2" hickory-resolver = "0.25.0-alpha.2" -hickory-server = { version = "0.25.0-alpha.2", features = ["dns-over-rustls", "dns-over-https-rustls", "dns-over-h3"] } hickory-proto = { version = "0.25.0-alpha.2", features = ["dns-over-rustls", "dns-over-https-rustls", "dns-over-h3"]} dhcproto = "0.12" diff --git a/clash_lib/src/app/api/handlers/dns.rs b/clash_lib/src/app/api/handlers/dns.rs index 93a26a63..e2dc3d99 100644 --- a/clash_lib/src/app/api/handlers/dns.rs +++ b/clash_lib/src/app/api/handlers/dns.rs @@ -52,7 +52,7 @@ async fn query_dns( m.add_query(hickory_proto::op::Query::query(name.unwrap(), typ)); - match state.resolver.exchange(m).await { + match state.resolver.exchange(&m).await { Ok(response) => { let mut resp = Map::new(); resp.insert("Status".to_owned(), response.response_code().low().into()); diff --git a/clash_lib/src/app/dns/config.rs b/clash_lib/src/app/dns/config.rs index 46169593..c1642b64 100644 --- a/clash_lib/src/app/dns/config.rs +++ b/clash_lib/src/app/dns/config.rs @@ -10,6 +10,7 @@ use regex::Regex; use serde::Deserialize; use url::Url; +use watfaq_dns::{DNSListenAddr, DoH3Config, DoHConfig, DoTConfig}; use crate::{ common::trie, @@ -45,44 +46,6 @@ pub struct FallbackFilter { pub domain: Vec, } -#[derive(Debug, Deserialize, Clone)] -#[serde(rename_all = "kebab-case")] -pub struct DoHConfig { - pub addr: SocketAddr, - pub ca_cert: DnsServerCert, - pub ca_key: DnsServerKey, - pub hostname: Option, -} - -#[derive(Debug, Deserialize, Clone)] -#[serde(rename_all = "kebab-case")] -pub struct DoH3Config { - pub addr: SocketAddr, - pub ca_cert: DnsServerCert, - pub ca_key: DnsServerKey, - pub hostname: Option, -} - -#[derive(Debug, Deserialize, Clone)] -#[serde(rename_all = "kebab-case")] -pub struct DoTConfig { - pub addr: SocketAddr, - pub ca_cert: DnsServerCert, - pub ca_key: DnsServerKey, -} - -pub type DnsServerKey = Option; -pub type DnsServerCert = Option; - -#[derive(Debug, Default, Clone)] -pub struct DNSListenAddr { - pub udp: Option, - pub tcp: Option, - pub doh: Option, - pub dot: Option, - pub doh3: Option, -} - #[derive(Default)] pub struct Config { pub enable: bool, diff --git a/clash_lib/src/app/dns/mod.rs b/clash_lib/src/app/dns/mod.rs index 5b62a8e9..31a116a1 100644 --- a/clash_lib/src/app/dns/mod.rs +++ b/clash_lib/src/app/dns/mod.rs @@ -65,16 +65,15 @@ pub trait ClashResolver: Sync + Send { async fn cached_for(&self, ip: std::net::IpAddr) -> Option; /// Used for DNS Server - async fn exchange(&self, message: op::Message) -> anyhow::Result; + async fn exchange(&self, message: &op::Message) -> anyhow::Result; /// Only used for look up fake IP async fn reverse_lookup(&self, ip: std::net::IpAddr) -> Option; async fn is_fake_ip(&self, ip: std::net::IpAddr) -> bool; + fn fake_ip_enabled(&self) -> bool; fn ipv6(&self) -> bool; fn set_ipv6(&self, enable: bool); fn kind(&self) -> ResolverKind; - - fn fake_ip_enabled(&self) -> bool; } diff --git a/clash_lib/src/app/dns/resolver/enhanced.rs b/clash_lib/src/app/dns/resolver/enhanced.rs index ea46952e..3a7612fa 100644 --- a/clash_lib/src/app/dns/resolver/enhanced.rs +++ b/clash_lib/src/app/dns/resolver/enhanced.rs @@ -437,7 +437,7 @@ impl EnhancedResolver { fn domain_name_of_message(m: &op::Message) -> Option { m.query() - .map(|x| x.name().to_ascii().trim_matches('.').to_owned()) + .map(|x| x.name().to_ascii().trim_end_matches('.').to_owned()) } pub(crate) fn ip_list_of_message(m: &op::Message) -> Vec { @@ -581,8 +581,8 @@ impl ClashResolver for EnhancedResolver { None } - async fn exchange(&self, message: op::Message) -> anyhow::Result { - let rv = self.exchange(&message).await?; + async fn exchange(&self, message: &op::Message) -> anyhow::Result { + let rv = self.exchange(message).await?; let hostname = message .query() .unwrap() diff --git a/clash_lib/src/app/dns/resolver/system_linux.rs b/clash_lib/src/app/dns/resolver/system_linux.rs index 44567ccd..90a512c8 100644 --- a/clash_lib/src/app/dns/resolver/system_linux.rs +++ b/clash_lib/src/app/dns/resolver/system_linux.rs @@ -62,7 +62,7 @@ impl ClashResolver for SystemResolver { async fn exchange( &self, - _: hickory_proto::op::Message, + _: &hickory_proto::op::Message, ) -> anyhow::Result { Err(anyhow::anyhow!("unsupported")) } diff --git a/clash_lib/src/app/dns/resolver/system_non_linux.rs b/clash_lib/src/app/dns/resolver/system_non_linux.rs index c306860a..ce137d38 100644 --- a/clash_lib/src/app/dns/resolver/system_non_linux.rs +++ b/clash_lib/src/app/dns/resolver/system_non_linux.rs @@ -81,7 +81,7 @@ impl ClashResolver for SystemResolver { async fn exchange( &self, - _: hickory_proto::op::Message, + _: &hickory_proto::op::Message, ) -> anyhow::Result { Err(anyhow::anyhow!("unsupported")) } diff --git a/clash_lib/src/app/dns/server/dummy_keys.rs b/clash_lib/src/app/dns/server/dummy_keys.rs deleted file mode 100644 index 80fdf85c..00000000 --- a/clash_lib/src/app/dns/server/dummy_keys.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! Test certificate and key -//! host: dns.example.com - -pub static TEST_CERT: &str = include_str!("test/test.cert"); - -pub static TEST_KEY: &str = include_str!("test/test.key"); diff --git a/clash_lib/src/app/dns/server/mod.rs b/clash_lib/src/app/dns/server/mod.rs index 248a3ada..9d7bc7e0 100644 --- a/clash_lib/src/app/dns/server/mod.rs +++ b/clash_lib/src/app/dns/server/mod.rs @@ -1,93 +1,51 @@ -mod dummy_keys; -mod utils; - -use std::{net::IpAddr, time::Duration}; - -use async_trait::async_trait; +use std::net::IpAddr; use hickory_proto::{ - op::{Header, Message, MessageType, OpCode, ResponseCode}, + op::{Message, ResponseCode}, rr::{ rdata::{A, AAAA}, - RData, Record, RecordType, + RData, Record, }, }; -use hickory_server::{ - authority::MessageResponseBuilder, - server::{Request, RequestHandler, ResponseHandler, ResponseInfo}, - ServerFuture, -}; -use thiserror::Error; -use tokio::net::{TcpListener, UdpSocket}; -use tracing::{debug, error, info, warn}; -use utils::{load_default_cert, load_default_key}; + +use tracing::{debug, error}; +use watfaq_dns::DNSListenAddr; use crate::Runner; -use super::{config::DNSListenAddr, ThreadSafeDNSResolver}; +use super::ThreadSafeDNSResolver; static DEFAULT_DNS_SERVER_TTL: u32 = 60; -struct DnsListener { - server: ServerFuture, -} - -struct DnsHandler { +struct DnsMessageExchanger { resolver: ThreadSafeDNSResolver, } -#[derive(Error, Debug)] -pub enum DNSError { - #[error(transparent)] - Io(#[from] std::io::Error), - #[error("invalid OP code: {0}")] - InvalidOpQuery(String), - #[error("query failed: {0}")] - QueryFailed(String), -} +impl watfaq_dns::DnsMessageExchanger for DnsMessageExchanger { + fn ipv6(&self) -> bool { + self.resolver.ipv6() + } -impl DnsHandler { - async fn handle( + async fn exchange( &self, - request: &Request, - mut response_handle: R, - ) -> Result { - if request.op_code() != OpCode::Query { - return Err(DNSError::InvalidOpQuery(format!( - "invalid OP code: {}", - request.op_code() - ))); - } - - if request.message_type() != MessageType::Query { - return Err(DNSError::InvalidOpQuery(format!( - "invalid message type: {}", - request.message_type() - ))); - } - - let builder = MessageResponseBuilder::from_message_request(request); - let mut header = Header::response_from_request(request.header()); - - if request.query().query_type() == RecordType::AAAA && !self.resolver.ipv6() - { - header.set_authoritative(true); - - let resp = builder.build_no_records(header); - return Ok(response_handle.send_response(resp).await?); - } - + message: &Message, + ) -> Result { if self.resolver.fake_ip_enabled() { - let name = request.query().name(); - let host = if name.is_fqdn() { - name.to_string().strip_suffix('.').unwrap().to_string() - } else { - name.to_string() - }; - - let builder = MessageResponseBuilder::from_message_request(request); - let mut header = Header::response_from_request(request.header()); - header.set_authoritative(true); + let name = message + .query() + .ok_or(watfaq_dns::DNSError::InvalidOpQuery( + "malformed query message".to_string(), + ))? + .name(); + + let host = message + .query() + .map(|x| x.name().to_ascii().trim_end_matches('.').to_owned()) + .unwrap(); + + let mut message = Message::new(); + message.set_recursion_available(false); + message.set_authoritative(true); match self.resolver.resolve(&host, true).await { Ok(resp) => match resp { @@ -98,444 +56,57 @@ impl DnsHandler { }; let records = vec![Record::from_rdata( - name.into(), + name.clone(), DEFAULT_DNS_SERVER_TTL, rdata, )]; - let resp = - builder.build(header, records.iter(), &[], &[], &[]); - return Ok(response_handle.send_response(resp).await?); + message.set_response_code(ResponseCode::NoError); + message.set_answer_count(records.len() as u16); + + message.add_answers(records); + + return Ok(message); } None => { - let resp = builder.build_no_records(header); - return Ok(response_handle.send_response(resp).await?); + message.set_response_code(ResponseCode::NXDomain); + return Ok(message); } }, Err(e) => { debug!("dns resolve error: {}", e); - return Err(DNSError::QueryFailed(e.to_string())); + return Err(watfaq_dns::DNSError::QueryFailed(e.to_string())); } } } - - let mut m = Message::new(); - m.set_op_code(request.op_code()); - m.set_message_type(request.message_type()); - m.set_recursion_desired(request.recursion_desired()); - m.add_query(request.query().original().clone()); - m.add_additionals(request.additionals().iter().map(Clone::clone)); - m.add_name_servers(request.name_servers().iter().map(Clone::clone)); - for sig0 in request.sig0() { - m.add_sig0(sig0.clone()); - } - if let Some(edns) = request.edns() { - m.set_edns(edns.clone()); - } - - match self.resolver.exchange(m).await { - Ok(m) => { - header.set_recursion_available(m.recursion_available()); - header.set_response_code(m.response_code()); - header.set_authoritative(m.authoritative()); - - header.set_answer_count(m.answer_count()); - header.set_name_server_count(m.name_server_count()); - header.set_additional_count(m.additional_count()); - - let mut rv = builder.build( - header, - m.answers(), - m.name_servers(), - &[], - m.additionals(), - ); - - if let Some(edns) = request.edns() { - if edns.dnssec_ok() { - if let Some(edns) = m.extensions() { - rv.set_edns(edns.clone()); - } - } - } - - debug!( - "answering dns query {} with answer {:?}", - request.query().name(), - m.answers(), - ); - - Ok(response_handle.send_response(rv).await?) - } + match self.resolver.exchange(message).await { + Ok(m) => Ok(m), Err(e) => { debug!("dns resolve error: {}", e); - Err(DNSError::QueryFailed(e.to_string())) + Err(watfaq_dns::DNSError::QueryFailed(e.to_string())) } } } } -#[async_trait] -impl RequestHandler for DnsHandler { - async fn handle_request( - &self, - request: &Request, - response_handle: R, - ) -> ResponseInfo { - debug!( - "got dns request [{}][{}][{}] from {}", - request.protocol(), - request.query().query_type(), - request.query().name(), - request.src() - ); - - match self.handle(request, response_handle).await { - Ok(info) => info, - Err(e) => { - debug!("dns request error: {}", e); - let mut h = Header::new(); - h.set_response_code(ResponseCode::ServFail); - h.into() - } - } - } -} - -static DEFAULT_DNS_SERVER_TIMEOUT: Duration = Duration::from_secs(5); - pub async fn get_dns_listener( listen: DNSListenAddr, resolver: ThreadSafeDNSResolver, cwd: &std::path::Path, ) -> Option { - let h = DnsHandler { resolver }; - let mut s = ServerFuture::new(h); - - let mut has_server = false; - - if let Some(addr) = listen.udp { - has_server = true; - UdpSocket::bind(addr) - .await - .map(|x| { - info!("UDP dns server listening on: {}", addr); - s.register_socket(x); - }) - .ok()?; - } - if let Some(addr) = listen.tcp { - has_server = true; - TcpListener::bind(addr) - .await - .map(|x| { - info!("TCP dns server listening on: {}", addr); - s.register_listener(x, DEFAULT_DNS_SERVER_TIMEOUT); - }) - .ok()?; - } - if let Some(c) = listen.doh { - has_server = true; - TcpListener::bind(c.addr) - .await - .and_then(|x| { - info!("DoH server listening on: {}", c.addr); - if let (Some(k), Some(c)) = (&c.ca_key, &c.ca_cert) { - debug!("using custom key and cert for doh: {}/{}", k, c); + let h = DnsMessageExchanger { resolver }; + let r = watfaq_dns::get_dns_listener(listen, h, cwd).await; + if let Some(r) = r { + Some(Box::pin(async move { + match r.await { + Ok(()) => Ok(()), + Err(err) => { + error!("dns listener error: {}", err); + Err(err.into()) } - - let server_key = c - .ca_key - .map(|x| utils::load_priv_key(&cwd.join(x))) - .transpose()? - .unwrap_or(load_default_key()); - let server_cert = c - .ca_cert - .map(|x| utils::load_cert_chain(&cwd.join(x))) - .transpose()? - .unwrap_or(load_default_cert()); - s.register_https_listener( - x, - DEFAULT_DNS_SERVER_TIMEOUT, - (server_cert, server_key), - c.hostname, - )?; - Ok(()) - }) - .ok()?; - } - if let Some(c) = listen.dot { - has_server = true; - TcpListener::bind(c.addr) - .await - .and_then(|x| { - info!("DoT dns server listening on: {}", c.addr); - if let (Some(k), Some(c)) = (&c.ca_key, &c.ca_cert) { - debug!("using custom key and cert for dot: {}/{}", k, c); - } - - let server_key = c - .ca_key - .map(|x| utils::load_priv_key(&cwd.join(x))) - .transpose()? - .unwrap_or(load_default_key()); - let server_cert = c - .ca_cert - .map(|x| utils::load_cert_chain(&cwd.join(x))) - .transpose()? - .unwrap_or(load_default_cert()); - s.register_tls_listener( - x, - DEFAULT_DNS_SERVER_TIMEOUT, - (server_cert, server_key), - )?; - Ok(()) - }) - .ok()?; - } - - if let Some(c) = listen.doh3 { - has_server = true; - UdpSocket::bind(c.addr) - .await - .and_then(|x| { - info!("DoT3 dns server listening on: {}", c.addr); - if let (Some(k), Some(c)) = (&c.ca_key, &c.ca_cert) { - debug!("using custom key and cert for dot: {}/{}", k, c); - } - - let server_key = c - .ca_key - .map(|x| utils::load_priv_key(&cwd.join(x))) - .transpose()? - .unwrap_or(load_default_key()); - let server_cert = c - .ca_cert - .map(|x| utils::load_cert_chain(&cwd.join(x))) - .transpose()? - .unwrap_or(load_default_cert()); - s.register_h3_listener( - x, - DEFAULT_DNS_SERVER_TIMEOUT, - (server_cert, server_key), - c.hostname, - )?; - Ok(()) - }) - .ok()?; - } - - if !has_server { - return None; - } - - let mut l = DnsListener { server: s }; - - Some(Box::pin(async move { - l.server.block_until_done().await.map_err(|x| { - warn!("dns server error: {}", x); - crate::Error::DNSError(format!("dns server error: {}", x)) - }) - })) -} - -#[cfg(test)] -mod tests { - use std::{sync::Arc, time::Duration}; - - use hickory_client::{ - client::{self, AsyncClient, ClientHandle}, - proto::iocompat::AsyncIoTokioAsStd, - }; - use hickory_proto::{ - h2::HttpsClientStreamBuilder, - h3::H3ClientStreamBuilder, - rr::{rdata::A, DNSClass, Name, RData, RecordType}, - rustls::tls_client_connect, - tcp::TcpClientStream, - udp::UdpClientStream, - }; - use rustls::ClientConfig; - use tokio::net::{TcpStream as TokioTcpStream, UdpSocket as TokioUdpSocket}; - - use crate::{ - app::dns::MockClashResolver, - common::tls::{self, GLOBAL_ROOT_STORE}, - tests::initialize, - }; - - async fn send_query(client: &mut AsyncClient) { - // Specify the name, note the final '.' which specifies it's an FQDN - let name = Name::from_ascii("www.example.com.").unwrap(); - - // NOTE: see 'Setup a connection' example above - // Send the query and get a message response, see RecordType for all - // supported options - let response = client - .query(name, DNSClass::IN, RecordType::A) - .await - .unwrap(); - - // Messages are the packets sent between client and server in DNS. - // there are many fields to a Message, DnsResponse can be dereferenced into - // a Message. It's beyond the scope of these examples - // to explain all the details of a Message. See - // hickory_client::op::message::Message for more details. generally - // we will be interested in the Message::answers - let answers = response.answers(); - - // Records are generic objects which can contain any data. - // In order to access it we need to first check what type of record it is - // In this case we are interested in A, IPv4 address - if let RData::A(ref ip) = answers[0].data() { - assert_eq!(*ip, A::new(93, 184, 215, 14)) - } else { - unreachable!("unexpected result") - } - } - - #[tokio::test] - async fn test_multiple_dns_server() { - initialize(); - - let mut resolver = MockClashResolver::new(); - resolver.expect_fake_ip_enabled().returning(|| false); - resolver.expect_exchange().returning(|_| { - let mut m = hickory_proto::op::Message::new(); - m.set_response_code(hickory_proto::op::ResponseCode::NoError); - m.add_answer(hickory_proto::rr::Record::from_rdata( - "www.example.com".parse().unwrap(), - 60, - hickory_proto::rr::RData::A(hickory_proto::rr::rdata::A( - std::net::Ipv4Addr::new(93, 184, 215, 14), - )), - )); - Ok(m) - }); - - let cfg = crate::app::dns::config::DNSListenAddr { - udp: Some("127.0.0.1:53553".parse().unwrap()), - tcp: Some("127.0.0.1:53554".parse().unwrap()), - dot: Some(crate::app::dns::config::DoTConfig { - addr: "127.0.0.1:53555".parse().unwrap(), - ca_key: None, - ca_cert: None, - }), - doh: Some(crate::app::dns::config::DoHConfig { - addr: "127.0.0.1:53556".parse().unwrap(), - hostname: Some("dns.example.com".to_string()), - ca_key: None, - ca_cert: None, - }), - doh3: Some(crate::app::dns::config::DoH3Config { - addr: "127.0.0.1:53556".parse().unwrap(), - hostname: Some("dns.example.com".to_string()), - ca_key: None, - ca_cert: None, - }), - }; - let listener = super::get_dns_listener( - cfg, - Arc::new(resolver), - std::path::Path::new("."), - ) - .await; - - assert!(listener.is_some()); - tokio::spawn(async move { - listener.unwrap().await.unwrap(); - }); - - let stream = UdpClientStream::::new( - "127.0.0.1:53553".parse().unwrap(), - ); - let (mut client, handle) = - client::AsyncClient::connect(stream).await.unwrap(); - tokio::spawn(handle); - - send_query(&mut client).await; - - let (stream, sender) = - TcpClientStream::>::new( - "127.0.0.1:53554".parse().unwrap(), - ); - - let (mut client, handle) = client::AsyncClient::new(stream, sender, None) - .await - .unwrap(); - tokio::spawn(handle); - - send_query(&mut client).await; - - let mut tls_config = ClientConfig::builder() - .with_root_certificates(GLOBAL_ROOT_STORE.clone()) - .with_no_client_auth(); - tls_config.alpn_protocols = vec!["h2".into()]; - tls_config - .dangerous() - .set_certificate_verifier(Arc::new(tls::DummyTlsVerifier::new())); - - let (stream, sender) = tls_client_connect::>( - "127.0.0.1:53555".parse().unwrap(), - "dns.example.com".to_owned(), - Arc::new(tls_config), - ); - - let (mut client, handle) = client::AsyncClient::with_timeout( - stream, - sender, - Duration::from_secs(5), - None, - ) - .await - .unwrap(); - tokio::spawn(handle); - - send_query(&mut client).await; - - let mut tls_config = ClientConfig::builder() - .with_root_certificates(GLOBAL_ROOT_STORE.clone()) - .with_no_client_auth(); - tls_config.alpn_protocols = vec!["h2".into()]; - - tls_config - .dangerous() - .set_certificate_verifier(Arc::new(tls::DummyTlsVerifier::new())); - - let stream = - HttpsClientStreamBuilder::with_client_config(Arc::new(tls_config)) - .build::>( - "127.0.0.1:53556".parse().unwrap(), - "dns.example.com".to_owned(), - ); - - let (mut client, handle) = - client::AsyncClient::connect(stream).await.unwrap(); - tokio::spawn(handle); - - send_query(&mut client).await; - - let mut tls_config = ClientConfig::builder() - .with_root_certificates(GLOBAL_ROOT_STORE.clone()) - .with_no_client_auth(); - tls_config.alpn_protocols = vec!["h3".into()]; - - tls_config - .dangerous() - .set_certificate_verifier(Arc::new(tls::DummyTlsVerifier::new())); - - let stream = H3ClientStreamBuilder::default() - .crypto_config(tls_config) - .clone() - .build( - "127.0.0.1:53556".parse().unwrap(), - "dns.example.com".to_owned(), - ); - - let (mut client, handle) = - client::AsyncClient::connect(stream).await.unwrap(); - tokio::spawn(handle); - - send_query(&mut client).await; + } + })) + } else { + None } } diff --git a/clash_lib/src/app/dns/server/test/test.cert b/clash_lib/src/app/dns/server/test/test.cert deleted file mode 100644 index 4d9a8729..00000000 --- a/clash_lib/src/app/dns/server/test/test.cert +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDITCCAgmgAwIBAgIQOp++4lLpVGLWkaGuRrrP2zANBgkqhkiG9w0BAQsFADAS -MRAwDgYDVQQKEwdBY21lIENvMB4XDTIzMDkwMjA4MzIyM1oXDTI0MDkwMTA4MzIy -M1owEjEQMA4GA1UEChMHQWNtZSBDbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAPS+pfYexKHq50myjnY6kAZ1uLDmgR/Vy9y7rPcrkqci25ClCnuUiUgY -ABhrdq16oW2wOymc9A56YH9X99UNX6E+VmckCP8v9xcPV4/Zoc+KIeuJHRUBHFMK -ieiWe560XcRCTP7OudUZ+iSHbjhaxZJCEfFaE8aSZXmiLKUETZ7z2lAm75fRCBaR -Vy+jewy04F1BKg4VlnrZnVHzQCcBHZEpsAz4YpbNHMYf9sYRrh+T2j9Zya5tUklI -LzEobWXUzjhrkcBXSVC5dLa9sxz7eSeg0dY0SkP7O5pelr8LaXnBudAk5B0ByqFD -s83Z1AZMkv7vL2L8AGA/X1PP2UV3BrECAwEAAaNzMHEwDgYDVR0PAQH/BAQDAgKk -MBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE -FIiHKw+Z9rUjV6pbqcDl+teSTLxoMBoGA1UdEQQTMBGCD2Rucy5leGFtcGxlLmNv -bTANBgkqhkiG9w0BAQsFAAOCAQEACTYIij1QqPhke3aI6HVLuXy75YHjxic0cIcX -7u41WSnZWOrnsBYAFPfjwH7sW6dX+5twUludSCSQ9Xyhl/tdQ0AKWJJNZ7irArS9 -kz2rU4u7YjtR4tuuRB2t+8UEcGA/m0EPhQfFbZedAy/Y2oc+RodwlqibVB/WCMOQ -BL4HS1wFaYZw9WhXk3nzb+wjBhvyEQkI9oeMqVYZLN/9kIY9QuGtDg5onFrVSgjZ -qiR7EfdICe8ogM6IiemQJfZ5SeWkoLpuRlaeVhqFFaFFeJ6cMTJ+Jluh6a3DGP91 -aRaPVO7r8gPq4mACua0HQcBfmH4VKS3hsQHdWDivRUT7xkZ/6g== ------END CERTIFICATE----- diff --git a/clash_lib/src/app/dns/server/test/test.key b/clash_lib/src/app/dns/server/test/test.key deleted file mode 100644 index eb2e6342..00000000 --- a/clash_lib/src/app/dns/server/test/test.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQD0vqX2HsSh6udJ -so52OpAGdbiw5oEf1cvcu6z3K5KnItuQpQp7lIlIGAAYa3ateqFtsDspnPQOemB/ -V/fVDV+hPlZnJAj/L/cXD1eP2aHPiiHriR0VARxTConolnuetF3EQkz+zrnVGfok -h244WsWSQhHxWhPGkmV5oiylBE2e89pQJu+X0QgWkVcvo3sMtOBdQSoOFZZ62Z1R -80AnAR2RKbAM+GKWzRzGH/bGEa4fk9o/WcmubVJJSC8xKG1l1M44a5HAV0lQuXS2 -vbMc+3knoNHWNEpD+zuaXpa/C2l5wbnQJOQdAcqhQ7PN2dQGTJL+7y9i/ABgP19T -z9lFdwaxAgMBAAECggEAaMFNYcoLmc5kjsvJZFtumAU9NyKCNDEbX/BIeUcCL12h -IwkxMnICTIRRTiJ5Gom5nKxotkgCwkupD/iEEIH345k9/EmVPDy4gvtDHEQnmSBj -ol/+vaXLDNQe8Rmv8d77n2xNbmbnbYn/4jDBgYeAtzhmW6qVelHg8y3x8/OikZyy -EB+ORiH/p4XN+3xBuEnFwBjQSHlayYVL8E68rp2wcKIeB2wo27Noh+VNqc2jks/l -h9V+cydCOHY2OQ0iepZwPmsVVjEObtckksBTFWgpc5ZH6Ctq1YjtTpcOey9FRzhZ -fuK9cj7bO5uW1duocgMPGsgiYMdvGyOCmM4tgp4lwQKBgQD+SXkzutxu0577g3Td -8BWYvksM6O3Lq8ZHKQtcxcNpp9S/fQ134IMErlykS1FJ5290KkHwQ4tojiOhtYQo -GOlmbS7USR2puhNzEWxmhi0CIyyWyRDECrVZVnLfcVxZrxpoh4LjZFA6nVRhZipN -oMig1zDhVmhvUTrTxVygFp9/aQKBgQD2ZLgGTK0kZ4npsUEL/ZantlZwEpY8S3TK -muLlcGx3EFwPrX558xhYSwkh/afNTcRekJkoBA9SXaioZNKlOD/XyIFq0OeurygB -gC8RdBs3xAjNHyj9qxajhuBqxxxTa/HmUnWqH2zDv20DcyvLTXjpRuFBxBj77ka9 -eVyGBxmsCQKBgQCC2tJpIWagDXyJl2tDbnHeqUY7vX3pSlr9cYysUASwUTJ02+hb -YQhrF0MLNMr/Cf7bu4c1Gb0ar9J8O8lnTPKGx/bKPVnrZprtovCyjaeJqwoeChf7 -mjsaXxc8DrzkVex0EA/17kAu+ZlbidSJIA0+X56CxxF0/0sTgUOaCipHyQKBgQDl -Bie7y0fhH9CkhRtWPufrimP8FnrJHsY3kRK4e/CGF5HLDNQUHK8TWuPpUXLJNbEC -yVtjQ6rOP7qGk/jslEVbmMca94Vy7OK9yl111rt58WDQ8VbTu1T2uWceOWeN7zdR -hHJUqJMbvHJjE4mwlpl+FGFLFTC38/qTIhyrhCwLqQKBgQDz67mt3XyD5HUT/GYn -A91ZGjWfh3YPXYkjOOjw1MWqeO7LQi6A8uWkfRFPWn/h3gECqItrWFogJixRyL+G -TWQ7SWmJctHD8YjU3E6tlPSWQhD2U75pZWtjpGAIYSdvS5V9Q+95jaKKhsYneThB -SNEnosgWOR5eg9c0FznaDn6nRw== ------END PRIVATE KEY----- diff --git a/clash_lib/src/app/dns/server/utils.rs b/clash_lib/src/app/dns/server/utils.rs deleted file mode 100644 index 93bbf0cd..00000000 --- a/clash_lib/src/app/dns/server/utils.rs +++ /dev/null @@ -1,39 +0,0 @@ -use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}; -use std::{fs, path::Path}; - -use crate::common::errors::new_io_error; - -use super::dummy_keys::{TEST_CERT, TEST_KEY}; - -pub fn load_cert_chain( - cert_path: &Path, -) -> std::io::Result>> { - let cert_chain = fs::read(cert_path)?; - if cert_path.extension().map_or(false, |x| x == "der") { - Ok(vec![CertificateDer::from(cert_chain)]) - } else { - rustls_pemfile::certs(&mut &*cert_chain).collect::>() - } -} - -pub fn load_priv_key(key_path: &Path) -> std::io::Result> { - let key = fs::read(key_path)?; - if key_path.extension().map_or(false, |x| x == "der") { - Ok(PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(key))) - } else { - rustls_pemfile::private_key(&mut &*key)? - .ok_or(new_io_error("no private key found")) - } -} - -pub fn load_default_cert() -> Vec> { - rustls_pemfile::certs(&mut TEST_CERT.as_bytes()) - .collect::>() - .unwrap() -} - -pub fn load_default_key() -> PrivateKeyDer<'static> { - rustls_pemfile::private_key(&mut TEST_KEY.as_bytes()) - .unwrap() - .unwrap() -} diff --git a/clash_lib/src/lib.rs b/clash_lib/src/lib.rs index 97fb7cd3..c8c14807 100644 --- a/clash_lib/src/lib.rs +++ b/clash_lib/src/lib.rs @@ -57,6 +57,8 @@ pub enum Error { ProfileError(String), #[error("dns error: {0}")] DNSError(String), + #[error(transparent)] + DNSServerError(#[from] watfaq_dns::DNSError), #[error("crypto error: {0}")] Crypto(String), #[error("operation error: {0}")]