Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions plugin/smartdns-ui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ hyper-util = { version = "0.1.20", features = ["full"] }
hyper-tungstenite = "0.18.0"
tokio = { version = "1.50.0", features = ["full"] }
serde = { version = "1.0.228", features = ["derive"] }
tokio-rustls = { version = "0.26.4", default-features = false, features = ["ring", "tls12"], optional = true }
tokio-rustls = { version = "0.26.4", default-features = false, features = ["ring", "tls12"] }
rustls = { version = "0.23.37", default-features = false, features = ["ring", "tls12"] }
rustls-pemfile = { version = "2.2.0", optional = true}
rustls-pemfile = { version = "2.2.0" }
serde_json = "1.0.149"
http-body-util = "0.1.3"
getopts = "0.2.24"
Expand All @@ -26,7 +26,6 @@ jsonwebtoken = { version = "10.3.0", features = ["rust_crypto"] }
matchit = "0.8.6"
futures = "0.3.32"
socket2 = "0.6.3"
cfg-if = "1.0.4"
urlencoding = "2.1.3"
chrono = "0.4.44"
nix = "0.30.1"
Expand All @@ -36,7 +35,7 @@ rand_core = { version = "0.6", features = ["std"] }

[features]
build-release = []
https = ["tokio-rustls", "rustls-pemfile"]
https = []
default = ["https"]

[dev-dependencies]
Expand Down
146 changes: 72 additions & 74 deletions plugin/smartdns-ui/src/http_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

extern crate cfg_if;

use crate::data_server::*;
use crate::dns_log;
use crate::http_api_msg::*;
Expand All @@ -38,6 +36,7 @@ use hyper_util::server::conn::auto;
use std::convert::Infallible;
use std::error::Error;
use std::fs::Metadata;
use std::io::BufReader;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::path::{Component, Path};
Expand All @@ -51,13 +50,7 @@ use tokio::net::TcpListener;
use tokio::net::TcpStream;
use tokio::sync::mpsc;
use tokio::task::JoinHandle;
cfg_if::cfg_if! {
if #[cfg(feature = "https")] {
use rustls_pemfile;
use std::io::BufReader;
use tokio_rustls::{rustls, TlsAcceptor};
}
}
use tokio_rustls::{rustls, TlsAcceptor};

const HTTP_SERVER_DEFAULT_PASSWORD: &str = "password";
const HTTP_SERVER_DEFAULT_USERNAME: &str = "admin";
Expand All @@ -74,6 +67,7 @@ pub struct HttpServerConfig {
pub token_expired_time: u32,
pub enable_cors: bool,
pub enable_terminal: bool,
pub https_port: u16,
}

impl HttpServerConfig {
Expand All @@ -92,6 +86,7 @@ impl HttpServerConfig {
token_expired_time: 600,
enable_cors: false,
enable_terminal: false,
https_port: 0,
}
}

Expand All @@ -108,6 +103,7 @@ impl HttpServerConfig {
"enable_terminal".to_string(),
self.enable_terminal.to_string(),
);
map.insert("https_port".to_string(), self.https_port.to_string());
map
}

Expand Down Expand Up @@ -146,6 +142,10 @@ impl HttpServerConfig {
}
}

if let Some(https_port) = data_server.get_server_config("smartdns-ui.https-port") {
self.https_port = https_port.parse::<u16>().unwrap_or(0);
}

Ok(())
}
}
Expand Down Expand Up @@ -411,18 +411,7 @@ impl HttpServer {
}

pub fn is_https_server(&self) -> bool {
let http_ip = self.get_conf().http_ip;
if http_ip.parse::<url::Url>().is_err() {
return false;
}

let binding = http_ip.parse::<url::Url>().unwrap();
let scheme = binding.scheme();
if scheme == "https" {
return true;
}

false
self.get_conf().https_port > 0
}

pub fn get_data_server(&self) -> Arc<DataServer> {
Expand Down Expand Up @@ -772,7 +761,6 @@ impl HttpServer {
});
}

#[cfg(feature = "https")]
async fn https_server_handle_conn(
this: Arc<HttpServer>,
stream: tokio_rustls::server::TlsStream<TcpStream>,
Expand All @@ -792,7 +780,6 @@ impl HttpServer {
});
}

#[cfg(feature = "https")]
async fn handle_tls_accept(this: Arc<HttpServer>, acceptor: TlsAcceptor, stream: TcpStream) {
tokio::task::spawn(async move {
let acceptor_future = acceptor.accept(stream);
Expand All @@ -819,54 +806,56 @@ impl HttpServer {
kickoff_tx: tokio::sync::oneshot::Sender<i32>,
) -> Result<(), Box<dyn Error>> {
let addr: String;
let https_port: u16;
let mut rx: mpsc::Receiver<()>;

{
let conf = this.conf.lock().unwrap();
addr = format!("{}", conf.http_ip);
https_port = conf.https_port;
let mut _rx = this.notify_rx.lock().unwrap();
rx = _rx.take().unwrap();
}

let url = addr.parse::<url::Url>()?;

cfg_if::cfg_if! {
if #[cfg(feature = "https")]
{
let mut acceptor = None;
if url.scheme() == "https" {
#[cfg(feature = "https")]
let cert_info = Plugin::smartdns_get_cert()?;

dns_log!(
LogLevel::DEBUG,
"cert: {}, key: {}",
cert_info.cert,
cert_info.key
);
let cert_chain: Result<Vec<rustls::pki_types::CertificateDer<'_>>, _> =
rustls_pemfile::certs(&mut BufReader::new(std::fs::File::open(
cert_info.cert,
)?))
.collect();
let cert_chain = cert_chain.unwrap_or_else(|_| Vec::new());
let key_der = rustls_pemfile::private_key(&mut BufReader::new(
std::fs::File::open(cert_info.key)?,
))?
.unwrap();

let mut config = rustls::ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(cert_chain, key_der)?;

config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
acceptor = Some(TlsAcceptor::from(Arc::new(config)));
}
} else {
if url.scheme() == "https" {
return Err("https is not supported.".into());
}
}
let mut acceptor = None;
let mut https_listener = None;
if https_port > 0 {
let cert_info = Plugin::smartdns_get_cert()?;

dns_log!(
LogLevel::DEBUG,
"cert: {}, key: {}",
cert_info.cert,
cert_info.key
);
let cert_chain: Result<Vec<rustls::pki_types::CertificateDer<'_>>, _> =
rustls_pemfile::certs(&mut BufReader::new(std::fs::File::open(cert_info.cert)?))
.collect();
let cert_chain = cert_chain.unwrap_or_else(|_| Vec::new());
let key_der = rustls_pemfile::private_key(&mut BufReader::new(std::fs::File::open(
cert_info.key,
)?))?
.unwrap();

let mut config = rustls::ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(cert_chain, key_der)?;

config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
acceptor = Some(TlsAcceptor::from(Arc::new(config)));

let https_sock_addr =
format!("{}:{}", url.host_str().unwrap_or("127.0.0.1"), https_port)
.parse::<SocketAddr>()?;
let listener = TcpListener::bind(https_sock_addr).await?;
dns_log!(
LogLevel::INFO,
"https server listen at {}",
listener.local_addr()?
);
https_listener = Some(listener);
}

let host = url.host_str().unwrap_or("127.0.0.1");
Expand Down Expand Up @@ -904,26 +893,35 @@ impl HttpServer {
if let Err(_) = sock_ref.set_send_buffer_size(262144) {
dns_log!(LogLevel::DEBUG, "Failed to set send buffer size");
}
cfg_if::cfg_if! {
if #[cfg(feature = "https")]
{
if acceptor.is_some() {
let acceptor = acceptor.clone().unwrap().clone();
let this_clone = this.clone();
HttpServer::handle_tls_accept(this_clone, acceptor, stream).await;
} else {
HttpServer::http_server_handle_conn(this.clone(), stream).await;
}
} else {
HttpServer::http_server_handle_conn(this.clone(), stream).await;
}
}
HttpServer::http_server_handle_conn(this.clone(), stream).await;
}
Err(e) => {
dns_log!(LogLevel::ERROR, "accept error: {}", e);
}
}
}
res = async {
if let Some(listener) = https_listener.as_mut() {
Some(listener.accept().await)
} else {
None
}
}, if https_listener.is_some() => {
if let Some(res) = res {
match res {
Ok((stream, _)) => {
if let Some(acceptor) = acceptor.as_ref() {
let acceptor = acceptor.clone();
let this_clone = this.clone();
HttpServer::handle_tls_accept(this_clone, acceptor, stream).await;
}
}
Err(e) => {
dns_log!(LogLevel::ERROR, "https accept error: {}", e);
}
}
}
}
}
}

Expand Down
16 changes: 15 additions & 1 deletion plugin/smartdns-ui/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ impl SmartdnsPlugin {
opts.optopt("r", "www-root", "http www root", "PATH");
opts.optopt("", "data-dir", "http data dir", "PATH");
opts.optopt("", "token-expire", "http token expire time", "TIME");
opts.optopt("", "https-port", "https server listen port", "PORT");
if args.len() <= 0 {
return Ok(());
}
Expand Down Expand Up @@ -132,6 +133,19 @@ impl SmartdnsPlugin {
http_conf.token_expired_time = v.unwrap();
}

let mut https_port = Plugin::dns_conf_plugin_config("smartdns-ui.https-port");
if https_port.is_none() {
https_port = matches.opt_str("https-port");
}
if let Some(https_port) = https_port {
let v = https_port.parse::<u16>();
if let Err(e) = v {
dns_log!(LogLevel::ERROR, "parse https port error: {}", e.to_string());
return Err(Box::new(e));
}
http_conf.https_port = v.unwrap();
}

if let Some(data_dir) = matches.opt_str("data-dir") {
data_conf.data_path = data_dir;
}
Expand Down Expand Up @@ -175,7 +189,7 @@ impl SmartdnsPlugin {
return;
}
*is_start = false;

dns_log!(LogLevel::INFO, "stop smartdns-ui server.");
self.http_server_ctl.stop_http_server();
self.data_server_ctl.stop_data_server();
Expand Down