| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152 |
- /*************************************************************************
- *
- * Copyright (C) 2018-2024 Ruilin Peng (Nick) <[email protected]>.
- *
- * smartdns is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * smartdns is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- use crate::db::*;
- use crate::dns_log;
- use crate::http_api_msg::*;
- use crate::http_error::*;
- use crate::http_jwt::*;
- use crate::http_server::*;
- use crate::http_server_stream;
- use crate::smartdns;
- use crate::smartdns::*;
- use crate::utils;
- use crate::Plugin;
- use bytes::Bytes;
- use http_body_util::BodyExt;
- use http_body_util::Full;
- use hyper::{body, Method, Request, Response, StatusCode};
- use matchit::Router;
- use std::collections::HashMap;
- use std::future::Future;
- use std::pin::Pin;
- use std::sync::Arc;
- use url::form_urlencoded;
- const PASSWORD_CONFIG_KEY: &str = "smartdns-ui.password";
- const REST_API_PATH: &str = "/api";
- type APIRouteFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
- type APIRouterFun = fn(
- this: Arc<HttpServer>,
- param: APIRouteParam,
- req: Request<body::Incoming>,
- ) -> APIRouteFuture<'static, Result<Response<Full<Bytes>>, HttpError>>;
- type APIRouteParam = HashMap<String, String>;
- pub struct APIRouter {
- pub method: Method,
- pub auth: bool,
- pub handler: APIRouterFun,
- }
- pub struct API {
- router: Router<std::collections::HashMap<Method, APIRouter>>,
- }
- macro_rules! APIRoute {
- ( $fn:path) => {
- |r, p, h| Box::pin($fn(r, p, h))
- };
- }
- #[allow(dead_code)]
- impl API {
- #[rustfmt::skip]
- pub fn new() -> Self {
- let mut api = API {
- router: Router::new(),
- };
- api.register(Method::PUT, "/api/service/restart", true, APIRoute!(API::api_service_restart));
- api.register(Method::PUT, "/api/cache/flush", true, APIRoute!(API::api_cache_flush));
- api.register(Method::GET, "/api/cache/count", true, APIRoute!(API::api_cache_count));
- api.register(Method::POST, "/api/auth/login", false, APIRoute!(API::api_auth_login));
- api.register(Method::POST, "/api/auth/logout", false, APIRoute!(API::api_auth_logout));
- api.register(Method::GET, "/api/auth/check", true, APIRoute!(API::api_auth_check));
- api.register(Method::PUT, "/api/auth/password", false, APIRoute!(API::api_auth_change_password));
- api.register(Method::POST, "/api/auth/refresh", true, APIRoute!(API::api_auth_refresh));
- api.register(Method::GET, "/api/domain", true, APIRoute!(API::api_domain_get_list));
- api.register(Method::DELETE, "/api/domain", true, APIRoute!(API::api_domain_delete_list));
- api.register(Method::GET, "/api/domain/count", true, APIRoute!(API::api_domain_get_list_count));
- api.register(Method::GET, "/api/domain/{id}", true, APIRoute!(API::api_domain_get_by_id));
- api.register(Method::DELETE, "/api/domain/{id}", true, APIRoute!(API::api_domain_delete_by_id));
- api.register(Method::GET, "/api/client", true, APIRoute!(API::api_client_get_list));
- api.register(Method::DELETE, "/api/client/{id}", true, APIRoute!(API::api_client_delete_by_id));
- api.register(Method::GET, "/api/log/stream", true, APIRoute!(API::api_log_stream));
- api.register(Method::PUT, "/api/log/level", true, APIRoute!(API::api_log_set_level));
- api.register(Method::GET, "/api/log/level", true, APIRoute!(API::api_log_get_level));
- api.register(Method::GET, "/api/server/version", false, APIRoute!(API::api_server_version));
- api.register(Method::GET, "/api/upstream-server", true, APIRoute!(API::api_upstream_server_get_list));
- api.register(Method::GET, "/api/config/settings", true, APIRoute!(API::api_config_get_settings));
- api.register(Method::PUT, "/api/config/settings", true, APIRoute!(API::api_config_set_settings));
- api.register(Method::GET, "/api/stats/top/client", true, APIRoute!(API::api_stats_get_top_client));
- api.register(Method::GET, "/api/stats/top/domain", true, APIRoute!(API::api_stats_get_top_domain));
- api.register(Method::GET, "/api/stats/metrics", true, APIRoute!(API::api_stats_get_metrics));
- api.register(Method::GET, "/api/stats/overview", true, APIRoute!(API::api_stats_get_overview));
- api.register(Method::GET, "/api/stats/hourly-query-count", true, APIRoute!(API::api_stats_get_hourly_query_count));
- api.register(Method::GET, "/api/stats/daily-query-count", true, APIRoute!(API::api_stats_get_daily_query_count));
- api.register(Method::PUT, "/api/stats/refresh", true, APIRoute!(API::api_stats_refresh));
- api.register(Method::GET, "/api/whois", true, APIRoute!(API::api_whois));
- api.register(Method::GET, "/api/tool/term", true, APIRoute!(API::api_tool_term));
- api
- }
- pub fn register(&mut self, method: Method, path: &str, auth: bool, handler: APIRouterFun) {
- let route_data = APIRouter {
- method: method.clone(),
- auth: auth,
- handler: handler,
- };
- let mut m = self.router.at_mut(path);
- if m.is_err() {
- let map_new = std::collections::HashMap::new();
- _ = self.router.insert(path, map_new);
- m = self.router.at_mut(path);
- if m.is_err() {
- return;
- }
- }
- let m = m.unwrap();
- let mutmethod_map = m.value;
- mutmethod_map.insert(method, route_data);
- }
- pub fn get_router(&self, method: &Method, path: &str) -> Option<(&APIRouter, APIRouteParam)> {
- let m = self.router.at(path);
- if m.is_err() {
- return None;
- }
- let m = m.unwrap();
- let method_map = m.value;
- let route_data = method_map.get(method);
- if route_data.is_none() {
- return None;
- }
- let route_data = route_data.unwrap();
- let mut param = APIRouteParam::new();
- m.params.iter().for_each(|(k, v)| {
- let v = v.to_string();
- param.insert(k.to_string(), v);
- });
- Some((route_data, param))
- }
- fn get_params(req: &Request<body::Incoming>) -> HashMap<String, String> {
- let b = req.uri().query().unwrap_or("").to_string();
- form_urlencoded::parse(b.as_ref())
- .into_owned()
- .collect::<HashMap<String, String>>()
- }
- fn params_parser_value<T: std::str::FromStr>(v: Option<&String>) -> Option<T> {
- if v.is_none() {
- return None;
- }
- let v = v.unwrap();
- match T::from_str(&v) {
- Ok(value) => Some(value),
- Err(_) => None,
- }
- }
- fn params_get_value<T: std::str::FromStr>(
- params: &HashMap<String, String>,
- key: &str,
- ) -> Option<T> {
- let v = params.get(key);
- if v.is_none() {
- return None;
- }
- let v = v.unwrap();
- API::params_parser_value(Some(v))
- }
- fn params_get_value_default<T: std::str::FromStr>(
- params: &HashMap<String, String>,
- key: &str,
- default: T,
- ) -> Result<T, HttpError> {
- let v = params.get(key);
- if v.is_none() {
- return Ok(default);
- }
- let v = v.unwrap();
- match v.parse::<T>() {
- Ok(v) => return Ok(v),
- Err(_) => {
- return Err(HttpError::new(
- StatusCode::BAD_REQUEST,
- format!("Invalid parameter: {}", key),
- ));
- }
- }
- }
- pub fn response_error(code: StatusCode, msg: &str) -> Result<Response<Full<Bytes>>, HttpError> {
- let bytes = Bytes::from(api_msg_error(msg));
- let mut response = Response::new(Full::new(bytes));
- response
- .headers_mut()
- .insert("Content-Type", "application/json".parse().unwrap());
- *response.status_mut() = code;
- Ok(response)
- }
- pub fn response_build(
- code: StatusCode,
- body: String,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let mut response = Response::new(Full::new(Bytes::from(body)));
- response
- .headers_mut()
- .insert("Content-Type", "application/json".parse().unwrap());
- *response.status_mut() = code;
- Ok(response)
- }
- async fn api_auth_refresh(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let token = HttpServer::get_token_from_header(&req)?;
- let unauth_response =
- || API::response_error(StatusCode::UNAUTHORIZED, "Incorrect username or password.");
- if token.is_none() {
- return unauth_response();
- }
- let token = token.unwrap();
- let conf = this.get_conf();
- let jtw = Jwt::new(
- &conf.username.as_str(),
- conf.password.as_str(),
- "",
- conf.token_expired_time,
- );
- let calim = jtw.decode_token(token.as_str());
- if calim.is_err() {
- return unauth_response();
- }
- let token_new = jtw.refresh_token(token.as_str());
- if token_new.is_err() {
- return unauth_response();
- }
- let token_new = token_new.unwrap();
- let mut resp = API::response_build(
- StatusCode::OK,
- api_msg_auth_token(&token_new.token, &token_new.expire),
- );
- let cookie_token = format!("Bearer {}", token_new.token);
- let token_urlencode = urlencoding::encode(cookie_token.as_str());
- let cookie = format!(
- "token={}; HttpOnly; Max-Age={}; Path={}",
- token_urlencode, token_new.expire, REST_API_PATH
- );
- resp.as_mut()
- .unwrap()
- .headers_mut()
- .insert(hyper::header::SET_COOKIE, cookie.parse().unwrap());
- resp
- }
- /// Login
- /// API: POST /api/auth/login
- /// body:
- /// {
- /// "username": "admin"
- /// "password": "password"
- /// }
- async fn api_auth_login(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let whole_body = String::from_utf8(req.into_body().collect().await?.to_bytes().into())?;
- let userinfo = api_msg_parse_auth(whole_body.as_str());
- if let Err(e) = userinfo {
- return API::response_error(StatusCode::BAD_REQUEST, e.to_string().as_str());
- }
- let conf = this.get_conf();
- let userinfo = userinfo.unwrap();
- if !this.login_attempts_check() {
- return API::response_error(
- StatusCode::FORBIDDEN,
- "Too many login attempts, please try again later.",
- );
- }
- if userinfo.username != conf.username
- || utils::verify_password(userinfo.password.as_str(), conf.password.as_str()) != true
- {
- return API::response_error(
- StatusCode::UNAUTHORIZED,
- "Incorrect username or password.",
- );
- }
- this.login_attempts_reset();
- let jtw = Jwt::new(
- userinfo.username.as_str(),
- conf.password.as_str(),
- "",
- conf.token_expired_time,
- );
- let token = jtw.encode_token();
- let mut resp = API::response_build(
- StatusCode::OK,
- api_msg_auth_token(&token.token, &token.expire),
- );
- let cookie_token = format!("Bearer {}", token.token);
- let token_urlencode = urlencoding::encode(cookie_token.as_str());
- let cookie = format!(
- "token={}; HttpOnly; Max-Age={}; Path={}",
- token_urlencode, token.expire, REST_API_PATH
- );
- resp.as_mut()
- .unwrap()
- .headers_mut()
- .insert(hyper::header::SET_COOKIE, cookie.parse().unwrap());
- resp
- }
- async fn api_auth_logout(
- _this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let mut response = Response::new(Full::new(Bytes::from("")));
- let cookie = format!("token=none; HttpOnly; Max-Age=1; Path={}", REST_API_PATH);
- response
- .headers_mut()
- .insert(hyper::header::SET_COOKIE, cookie.parse().unwrap());
- *response.status_mut() = StatusCode::NO_CONTENT;
- Ok(response)
- }
- async fn api_auth_check(
- _this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- API::response_build(StatusCode::OK, "".to_string())
- }
- async fn api_auth_change_password(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let unauth_response =
- || API::response_error(StatusCode::UNAUTHORIZED, "Incorrect username or password.");
- let token = HttpServer::get_token_from_header(&req)?;
- let whole_body = String::from_utf8(req.into_body().collect().await?.to_bytes().into())?;
- if token.is_none() {
- return unauth_response();
- }
- let password_info = match api_msg_parse_auth_password_change(whole_body.as_str()) {
- Ok(v) => v,
- Err(e) => {
- return API::response_error(StatusCode::BAD_REQUEST, e.to_string().as_str());
- }
- };
- if !this.login_attempts_check() {
- return API::response_error(
- StatusCode::FORBIDDEN,
- "Too many login attempts, please try again later.",
- );
- }
- let mut conf = this.get_conf_mut();
- if utils::verify_password(password_info.0.as_str(), conf.password.as_str()) != true {
- return API::response_error(StatusCode::FORBIDDEN, "Incorrect password.");
- }
- let hashed_password = match utils::hash_password(password_info.1.as_str(), Some(10000)) {
- Ok(v) => v,
- Err(e) => {
- return API::response_error(
- StatusCode::INTERNAL_SERVER_ERROR,
- e.to_string().as_str(),
- );
- }
- };
- let data_server = this.get_data_server();
- conf.password = hashed_password.clone();
- let ret = data_server.set_config(PASSWORD_CONFIG_KEY, hashed_password.as_str());
- if let Err(e) = ret {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- }
- this.login_attempts_reset();
- API::response_build(StatusCode::NO_CONTENT, "".to_string())
- }
- /// Restart the service <br>
- /// API: PUT /api/service/restart
- ///
- async fn api_service_restart(
- _this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let mut response = Response::new(Full::new(Bytes::from("")));
- response
- .headers_mut()
- .insert("Content-Type", "application/json".parse().unwrap());
- *response.status_mut() = StatusCode::NO_CONTENT;
- Plugin::smartdns_restart();
- Ok(response)
- }
- /// Get the number of cache <br>
- /// API: GET /api/cache/count
- ///
- async fn api_cache_count(
- _this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- API::response_build(
- StatusCode::OK,
- api_msg_gen_cache_number(Plugin::dns_cache_total_num()),
- )
- }
- /// Flush the cache <br>
- /// API: PUT /api/cache/flush
- ///
- async fn api_cache_flush(
- _this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- Plugin::dns_cache_flush();
- API::response_build(
- StatusCode::OK,
- api_msg_gen_cache_number(Plugin::dns_cache_total_num()),
- )
- }
- /// Get the number of domain list <br>
- /// API: GET /api/domain/count
- ///
- async fn api_domain_get_list_count(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let data_server = this.get_data_server();
- let count = data_server.get_domain_list_count();
- let body = api_msg_gen_count(count as i64);
- API::response_build(StatusCode::OK, body)
- }
- /// Get the domain by id <br>
- /// API: GET /api/domain/{id}
- async fn api_domain_get_by_id(
- this: Arc<HttpServer>,
- param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let id = API::params_parser_value(param.get("id"));
- if id.is_none() {
- return API::response_error(StatusCode::BAD_REQUEST, "Invalid parameter.");
- }
- let id = id.unwrap();
- let mut get_param = DomainListGetParam::new();
- get_param.id = Some(id);
- let data_server = this.get_data_server();
- let domain_list = data_server.get_domain_list(&get_param)?;
- if domain_list.domain_list.len() == 0 {
- return API::response_error(StatusCode::NOT_FOUND, "Not found");
- }
- let body = api_msg_gen_domain(&domain_list.domain_list[0]);
- API::response_build(StatusCode::OK, body)
- }
- /// Delete the client by id <br>
- /// API: DELETE /api/client/{id}
- /// parameter: <br>
- async fn api_client_delete_by_id(
- this: Arc<HttpServer>,
- param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let id = match API::params_parser_value(param.get("id")) {
- Some(v) => v,
- None => return API::response_error(StatusCode::BAD_REQUEST, "Invalid parameter."),
- };
- let data_server = this.get_data_server();
- let ret = match data_server.delete_client_by_id(id) {
- Ok(v) => v,
- Err(e) => {
- return API::response_error(
- StatusCode::INTERNAL_SERVER_ERROR,
- e.to_string().as_str(),
- )
- }
- };
- if ret == 0 {
- return API::response_error(StatusCode::NOT_FOUND, "Not found");
- }
- API::response_build(StatusCode::NO_CONTENT, "".to_string())
- }
- /// Delete the domain by id <br>
- /// API: DELETE /api/domain/{id}
- ///
- async fn api_domain_delete_by_id(
- this: Arc<HttpServer>,
- param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let id = match API::params_parser_value(param.get("id")) {
- Some(v) => v,
- None => return API::response_error(StatusCode::BAD_REQUEST, "Invalid parameter."),
- };
- let data_server = this.get_data_server();
- let ret = match data_server.delete_domain_by_id(id) {
- Ok(v) => v,
- Err(e) => {
- return API::response_error(
- StatusCode::INTERNAL_SERVER_ERROR,
- e.to_string().as_str(),
- )
- }
- };
- if ret == 0 {
- return API::response_error(StatusCode::NOT_FOUND, "Not found");
- }
- API::response_build(StatusCode::NO_CONTENT, "".to_string())
- }
- /// Get the domain list <br>
- /// API: GET /api/domain <br>
- /// parameter: <br>
- /// page_num: u32: Page number <br>
- /// page_size: u32: Page size <br>
- /// domain: String: Domain <br>
- /// domain_type: String: Domain type <br>
- /// domain_group: String: Domain group <br>
- /// client: String: Client <br>
- /// reply_code: String: Reply code <br>
- ///
- ///
- async fn api_domain_get_list(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let params = API::get_params(&req);
- let page_num = API::params_get_value_default(¶ms, "page_num", 1 as u64)?;
- let page_size = API::params_get_value_default(¶ms, "page_size", 10 as u64)?;
- if page_num == 0 || page_size == 0 {
- return API::response_error(
- StatusCode::BAD_REQUEST,
- "Invalid parameter: page_num or page_size",
- );
- }
- let id = API::params_get_value(¶ms, "id");
- let domain = API::params_get_value(¶ms, "domain");
- let domain_filter_mode = API::params_get_value(¶ms, "domain_filter_mode");
- let domain_type = API::params_get_value(¶ms, "domain_type");
- let domain_group = API::params_get_value(¶ms, "domain_group");
- let client = API::params_get_value(¶ms, "client");
- let reply_code = API::params_get_value(¶ms, "reply_code");
- let order = API::params_get_value(¶ms, "order");
- let is_blocked = API::params_get_value(¶ms, "is_blocked");
- let timestamp_after = API::params_get_value(¶ms, "timestamp_after");
- let timestamp_before = API::params_get_value(¶ms, "timestamp_before");
- let cursor = API::params_get_value(¶ms, "cursor");
- let cursor_direction =
- match API::params_get_value_default(¶ms, "cursor_direction", "next".to_string()) {
- Ok(v) => v,
- Err(e) => {
- return Ok(e.to_response());
- }
- };
- let total_count = API::params_get_value(¶ms, "total_count");
- let mut param = DomainListGetParam::new();
- param.id = id;
- param.page_num = page_num;
- param.page_size = page_size;
- param.domain = domain;
- param.domain_filter_mode = domain_filter_mode;
- param.domain_type = domain_type;
- param.domain_group = domain_group;
- param.client = client;
- param.reply_code = reply_code;
- param.order = order;
- param.is_blocked = is_blocked;
- param.timestamp_after = timestamp_after;
- param.timestamp_before = timestamp_before;
- if cursor.is_some() || total_count.is_some() {
- let param_cursor = DomainListGetParamCursor {
- id: if cursor.is_some() { cursor } else { None },
- total_count: total_count.unwrap(),
- direction: cursor_direction,
- };
- param.cursor = Some(param_cursor);
- }
- let data_server = this.get_data_server();
- let ret = API::call_blocking(this, move || {
- let ret = data_server
- .get_domain_list(¶m)
- .map_err(|e| e.to_string());
- if let Err(e) = ret {
- return Err(e.to_string());
- }
- let ret = ret.unwrap();
- return Ok(ret);
- })
- .await;
- if let Err(e) = ret {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- }
- let ret = ret.unwrap();
- if let Err(e) = ret {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- }
- let domain_list = ret.unwrap();
- let list_count = domain_list.total_count;
- let mut total_page = list_count / page_size;
- if list_count % page_size != 0 {
- total_page += 1;
- }
- let total_count = domain_list.total_count;
- let body = api_msg_gen_domain_list(&domain_list, total_page, total_count);
- API::response_build(StatusCode::OK, body)
- }
- /// Delete the domain list before timestamp <br>
- /// API: DELETE /api/domain <br>
- /// parameter: <br>
- /// timestamp: u64: Unix timestamp <br>
- ///
- async fn api_domain_delete_list(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let params = API::get_params(&req);
- let timestamp_before = API::params_get_value(¶ms, "timestamp_before");
- if timestamp_before.is_none() {
- return API::response_error(StatusCode::BAD_REQUEST, "Invalid parameter.");
- }
- let timestamp_before = timestamp_before.unwrap();
- let data_server = this.get_data_server();
- let ret = data_server.delete_domain_before_timestamp(timestamp_before);
- if let Err(e) = ret {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- }
- if *ret.as_ref().unwrap() == 0 {
- return API::response_error(StatusCode::NOT_FOUND, "Not found");
- }
- let body = api_msg_gen_count(ret.unwrap() as i64);
- API::response_build(StatusCode::OK, body)
- }
- async fn api_client_get_list(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let data_server = this.get_data_server();
- let ret = API::call_blocking(this, move || {
- let ret = data_server.get_client_list();
- if let Err(e) = ret {
- return Err(e.to_string());
- }
- let ret = ret.unwrap();
- return Ok(ret);
- }).await;
- let ret = match ret {
- Ok(v) => v,
- Err(e) => {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- },
- };
-
- if let Err(e) = ret {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- }
- let client_list = ret.unwrap();
- let body = api_msg_gen_client_list(&client_list, client_list.len() as u32);
- API::response_build(StatusCode::OK, body)
- }
- async fn api_log_stream(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- mut req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- if hyper_tungstenite::is_upgrade_request(&req) {
- let (response, websocket) = hyper_tungstenite::upgrade(&mut req, None)
- .map_err(|e| HttpError::new(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
- tokio::spawn(async move {
- if let Err(e) = http_server_stream::serve_log_stream(this, websocket).await {
- dns_log!(LogLevel::DEBUG, "Error in websocket connection: {e}");
- }
- });
- Ok(response)
- } else {
- return API::response_error(StatusCode::BAD_REQUEST, "Need websocket upgrade.");
- }
- }
- async fn api_log_set_level(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let whole_body = String::from_utf8(_req.into_body().collect().await?.to_bytes().into())?;
- let level = api_msg_parse_loglevel(whole_body.as_str());
- if let Err(e) = level {
- return API::response_error(StatusCode::BAD_REQUEST, e.to_string().as_str());
- }
- let level = level.unwrap();
- dns_log_set_level(level);
- let data_server = this.get_data_server();
- _ = data_server.set_config("log-level", level.to_string().as_str());
- API::response_build(StatusCode::NO_CONTENT, "".to_string())
- }
- async fn api_log_get_level(
- _this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let level = dns_log_get_level();
- let msg = api_msg_gen_loglevel(level);
- API::response_build(StatusCode::OK, msg)
- }
- async fn api_server_version(
- _this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let server_version = &smartdns::smartdns_version();
- let ui_version = &smartdns::smartdns_ui_version();
- let msg = api_msg_gen_version(server_version, ui_version);
- API::response_build(StatusCode::OK, msg)
- }
- async fn api_upstream_server_get_list(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let data_server = this.get_data_server();
- let upstream_server_list = data_server.get_upstream_server_list()?;
- let body = api_msg_gen_upstream_server_list(&upstream_server_list);
- API::response_build(StatusCode::OK, body)
- }
- async fn api_config_get_settings(
- this: Arc<HttpServer>,
- param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let key = API::params_get_value(¶m, "key");
- let data_server = this.get_data_server();
- let settings = data_server.get_config_list();
- if settings.is_err() {
- return API::response_error(StatusCode::NOT_FOUND, "Not found");
- }
- let mut settings = settings.unwrap();
- this.get_conf().settings_map().iter().for_each(|(k, v)| {
- if settings.get(k).is_none() {
- settings.insert(k.to_string(), v.to_string());
- }
- });
- let pass = settings.get(PASSWORD_CONFIG_KEY);
- if pass.is_some() {
- let pass = "********".to_string();
- settings.insert(PASSWORD_CONFIG_KEY.to_string(), pass);
- }
- if key.is_some() {
- let key : String = key.unwrap();
- let value = settings.get(key.as_str());
- if value.is_none() {
- return API::response_error(StatusCode::NOT_FOUND, "Not found");
- }
- let mut map = std::collections::HashMap::new();
- map.insert(key, value.unwrap().clone());
- let msg = api_msg_gen_key_value(&map);
- return API::response_build(StatusCode::OK, msg);
- }
- let msg = api_msg_gen_key_value(&settings);
- API::response_build(StatusCode::OK, msg)
- }
- async fn api_config_set_settings(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let data_server = this.get_data_server();
- let whole_body = String::from_utf8(req.into_body().collect().await?.to_bytes().into())?;
- let settings = api_msg_parse_key_value(whole_body.as_str());
- if let Err(e) = settings {
- return API::response_error(StatusCode::BAD_REQUEST, e.to_string().as_str());
- }
- let settings = settings.unwrap();
- for (key, value) in settings {
- if key == PASSWORD_CONFIG_KEY {
- continue;
- }
- let ret = data_server.set_config(key.as_str(), value.as_str());
- if let Err(e) = ret {
- return API::response_error(
- StatusCode::INTERNAL_SERVER_ERROR,
- e.to_string().as_str(),
- );
- }
- }
- API::response_build(StatusCode::NO_CONTENT, "".to_string())
- }
- async fn api_stats_get_top_client(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let data_server = this.get_data_server();
- let params = API::get_params(&_req);
- let count = API::params_get_value(¶ms, "count");
- let ret = API::call_blocking(this, move || {
- let ret = data_server.get_top_client_top_list(count);
- if let Err(e) = ret {
- return Err(e.to_string());
- }
- let ret = ret.unwrap();
- return Ok(ret);
- })
- .await;
- if let Err(e) = ret {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- }
- let ret = ret.unwrap();
- if let Err(e) = ret {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- }
- let body = api_msg_gen_top_client_list(&ret.unwrap());
- API::response_build(StatusCode::OK, body)
- }
- async fn api_stats_get_top_domain(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let data_server = this.get_data_server();
- let params = API::get_params(&_req);
- let count = API::params_get_value(¶ms, "count");
- let ret = API::call_blocking(this, move || {
- let ret = data_server.get_top_domain_top_list(count);
- if let Err(e) = ret {
- return Err(e.to_string());
- }
- let ret = ret.unwrap();
- return Ok(ret);
- })
- .await;
- if let Err(e) = ret {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- }
- let ret = ret.unwrap();
- if let Err(e) = ret {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- }
- let body = api_msg_gen_top_domain_list(&ret.unwrap());
- API::response_build(StatusCode::OK, body)
- }
- async fn api_stats_get_metrics(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- mut req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let data_server = this.get_data_server();
- if hyper_tungstenite::is_upgrade_request(&req) {
- let (response, websocket) = hyper_tungstenite::upgrade(&mut req, None)
- .map_err(|e| HttpError::new(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
- tokio::spawn(async move {
- if let Err(e) = http_server_stream::serve_metrics(data_server, websocket).await {
- dns_log!(LogLevel::DEBUG, "Error in websocket connection: {e}");
- }
- });
- Ok(response)
- } else {
- let metrics = data_server.get_metrics()?;
- let body = api_msg_gen_metrics_data(&metrics);
- return API::response_build(StatusCode::OK, body);
- }
- }
- async fn api_stats_get_overview(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let data_server = this.get_data_server();
- let overview = data_server.get_overview()?;
- let body = api_msg_gen_stats_overview(&overview);
- return API::response_build(StatusCode::OK, body);
- }
- async fn api_stats_refresh(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let data_server = this.get_data_server();
- let ret = API::call_blocking(this, move || -> Result<(), String> {
- data_server.get_stat().refresh();
- Ok(())
- })
- .await;
- if let Err(e) = ret {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- }
- API::response_build(StatusCode::NO_CONTENT, "".to_string())
- }
- async fn api_stats_get_daily_query_count(
- this: Arc<HttpServer>,
- param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let data_server = this.get_data_server();
- let past_days = API::params_get_value(¶m, "past_days");
- let ret = API::call_blocking(this, move || {
- let ret = data_server.get_daily_query_count(past_days);
- if let Err(e) = ret {
- return Err(e.to_string());
- }
- let ret = ret.unwrap();
- return Ok(ret);
- })
- .await;
- if let Err(e) = ret {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- }
- let ret = ret.unwrap();
- if let Err(e) = ret {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- }
- let body = api_msg_gen_daily_query_count(&ret.unwrap());
- API::response_build(StatusCode::OK, body)
- }
- async fn api_stats_get_hourly_query_count(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let params = API::get_params(&_req);
- let past_hours = API::params_get_value(¶ms, "past_hours");
- let data_server = this.get_data_server();
- let ret = API::call_blocking(this, move || {
- let ret = data_server.get_hourly_query_count(past_hours);
- if let Err(e) = ret {
- return Err(e.to_string());
- }
- let ret = ret.unwrap();
- return Ok(ret);
- })
- .await;
- if let Err(e) = ret {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- }
- let ret = ret.unwrap();
- if let Err(e) = ret {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- }
- let body = api_msg_gen_hourly_query_count(&ret.unwrap());
- API::response_build(StatusCode::OK, body)
- }
- async fn api_whois(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- _req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- let params = API::get_params(&_req);
- let domain = API::params_get_value(¶ms, "domain");
- if domain.is_none() {
- return API::response_error(StatusCode::BAD_REQUEST, "Invalid parameter.");
- }
- let domain: String = domain.unwrap();
- let data_server = this.get_data_server();
- let ret = data_server.whois(domain.as_str()).await;
- if let Err(e) = ret {
- return API::response_error(StatusCode::INTERNAL_SERVER_ERROR, e.to_string().as_str());
- }
- let body = api_msg_gen_whois_info(&ret.unwrap());
- API::response_build(StatusCode::OK, body)
- }
- async fn api_tool_term(
- this: Arc<HttpServer>,
- _param: APIRouteParam,
- mut req: Request<body::Incoming>,
- ) -> Result<Response<Full<Bytes>>, HttpError> {
- if this.get_conf().enable_terminal != true {
- return API::response_error(StatusCode::FORBIDDEN, "Terminal is disabled.");
- }
- if hyper_tungstenite::is_upgrade_request(&req) {
- let (response, websocket) = hyper_tungstenite::upgrade(&mut req, None)
- .map_err(|e| HttpError::new(StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
- tokio::spawn(async move {
- if let Err(e) = http_server_stream::serve_term(websocket).await {
- dns_log!(LogLevel::DEBUG, "Error in websocket connection: {e}");
- }
- });
- Ok(response)
- } else {
- return API::response_error(StatusCode::BAD_REQUEST, "Need websocket upgrade.");
- }
- }
- async fn call_blocking<F, R>(
- this: Arc<HttpServer>,
- func: F,
- ) -> Result<R, Box<dyn std::error::Error + Send>>
- where
- F: FnOnce() -> R + Send + 'static,
- R: Send + 'static,
- {
- let rt = this.get_data_server().get_plugin().get_runtime();
- let ret = rt.spawn_blocking(move || -> R {
- return func();
- });
- let ret = ret.await;
- if ret.is_err() {
- return Err(Box::new(ret.err().unwrap()));
- }
- let ret = ret.unwrap();
- return Ok(ret);
- }
- }
|