add feature to specify default backend
This commit is contained in:
parent
a6912e72bd
commit
3491b80142
9 changed files with 50 additions and 12 deletions
|
|
@ -5,6 +5,7 @@ listen_ipv6 = false
|
||||||
max_concurrent_streams = 128
|
max_concurrent_streams = 128
|
||||||
max_clients = 512
|
max_clients = 512
|
||||||
|
|
||||||
|
default_app = 'localhost' # passing through 127.0.0.1
|
||||||
|
|
||||||
[apps]
|
[apps]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,13 @@ max_clients = 512
|
||||||
|
|
||||||
listen_ipv6 = false
|
listen_ipv6 = false
|
||||||
|
|
||||||
|
# App that serves all plaintext http request by referring to HOSTS or request header
|
||||||
|
# execpt for configured application.
|
||||||
|
# Note that this is only for http.
|
||||||
|
# Note that nothing is served for requests via https since secure channel cannot be
|
||||||
|
# established for unconfigured server_name, and they are always rejected by checking SNI.
|
||||||
|
default_app = 'another_localhost'
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
# Backend settings #
|
# Backend settings #
|
||||||
###################################
|
###################################
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,11 @@ use std::{
|
||||||
};
|
};
|
||||||
use tokio_rustls::rustls::{Certificate, PrivateKey, ServerConfig};
|
use tokio_rustls::rustls::{Certificate, PrivateKey, ServerConfig};
|
||||||
|
|
||||||
|
pub struct Backends {
|
||||||
|
pub apps: HashMap<String, Backend>, // TODO: hyper::uriで抜いたhostで引っ掛ける。Stringでいいのか?
|
||||||
|
pub default_app: Option<String>, // for plaintext http
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
pub app_name: String,
|
pub app_name: String,
|
||||||
pub server_name: String,
|
pub server_name: String,
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use std::{collections::HashMap, sync::Mutex};
|
||||||
// #[cfg(feature = "tls")]
|
// #[cfg(feature = "tls")]
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub fn parse_opts(globals: &mut Globals, backends: &mut HashMap<String, Backend>) -> Result<()> {
|
pub fn parse_opts(globals: &mut Globals, backends: &mut Backends) -> Result<()> {
|
||||||
let _ = include_str!("../../Cargo.toml");
|
let _ = include_str!("../../Cargo.toml");
|
||||||
let options = clap::command!().arg(
|
let options = clap::command!().arg(
|
||||||
Arg::new("config_file")
|
Arg::new("config_file")
|
||||||
|
|
@ -110,7 +110,7 @@ pub fn parse_opts(globals: &mut Globals, backends: &mut HashMap<String, Backend>
|
||||||
ensure!(app.reverse_proxy.is_some(), "Missing reverse_proxy");
|
ensure!(app.reverse_proxy.is_some(), "Missing reverse_proxy");
|
||||||
let reverse_proxy = get_reverse_proxy(app.reverse_proxy.as_ref().unwrap())?;
|
let reverse_proxy = get_reverse_proxy(app.reverse_proxy.as_ref().unwrap())?;
|
||||||
|
|
||||||
backends.insert(
|
backends.apps.insert(
|
||||||
server_name.to_owned(),
|
server_name.to_owned(),
|
||||||
Backend {
|
Backend {
|
||||||
app_name: app_name.to_owned(),
|
app_name: app_name.to_owned(),
|
||||||
|
|
@ -125,6 +125,18 @@ pub fn parse_opts(globals: &mut Globals, backends: &mut HashMap<String, Backend>
|
||||||
);
|
);
|
||||||
info!("Registering application: {} ({})", app_name, server_name);
|
info!("Registering application: {} ({})", app_name, server_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// default backend application for plaintext http requests
|
||||||
|
if let Some(d) = config.default_app {
|
||||||
|
if backends.apps.contains_key(&d) {
|
||||||
|
info!(
|
||||||
|
"Serving plaintext http for requests to unconfigured server_name: {}.",
|
||||||
|
d
|
||||||
|
);
|
||||||
|
}
|
||||||
|
backends.default_app = Some(d);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ pub struct ConfigToml {
|
||||||
pub max_concurrent_streams: Option<u32>,
|
pub max_concurrent_streams: Option<u32>,
|
||||||
pub max_clients: Option<u32>,
|
pub max_clients: Option<u32>,
|
||||||
pub apps: Option<Apps>,
|
pub apps: Option<Apps>,
|
||||||
|
pub default_app: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Default)]
|
#[derive(Deserialize, Debug, Default)]
|
||||||
|
|
|
||||||
15
src/main.rs
15
src/main.rs
|
|
@ -10,7 +10,13 @@ mod log;
|
||||||
mod proxy;
|
mod proxy;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::Backend, config::parse_opts, constants::*, error::*, globals::*, log::*, proxy::Proxy,
|
backend::{Backend, Backends},
|
||||||
|
config::parse_opts,
|
||||||
|
constants::*,
|
||||||
|
error::*,
|
||||||
|
globals::*,
|
||||||
|
log::*,
|
||||||
|
proxy::Proxy,
|
||||||
};
|
};
|
||||||
use futures::future::select_all;
|
use futures::future::select_all;
|
||||||
use hyper::Client;
|
use hyper::Client;
|
||||||
|
|
@ -55,7 +61,10 @@ fn main() {
|
||||||
runtime_handle: runtime.handle().clone(),
|
runtime_handle: runtime.handle().clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut backends: HashMap<String, Backend> = HashMap::new();
|
let mut backends = Backends {
|
||||||
|
default_app: None,
|
||||||
|
apps: HashMap::<String, Backend>::new(),
|
||||||
|
};
|
||||||
|
|
||||||
let _ = parse_opts(&mut globals, &mut backends).expect("Invalid configuration");
|
let _ = parse_opts(&mut globals, &mut backends).expect("Invalid configuration");
|
||||||
|
|
||||||
|
|
@ -67,7 +76,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// entrypoint creates and spawns tasks of proxy services
|
// entrypoint creates and spawns tasks of proxy services
|
||||||
async fn entrypoint(globals: Arc<Globals>, backends: Arc<HashMap<String, Backend>>) -> Result<()> {
|
async fn entrypoint(globals: Arc<Globals>, backends: Arc<Backends>) -> Result<()> {
|
||||||
let connector = TrustDnsResolver::default().into_rustls_webpki_https_connector();
|
let connector = TrustDnsResolver::default().into_rustls_webpki_https_connector();
|
||||||
let forwarder = Arc::new(Client::builder().build::<_, hyper::Body>(connector));
|
let forwarder = Arc::new(Client::builder().build::<_, hyper::Body>(connector));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,11 @@ where
|
||||||
} else {
|
} else {
|
||||||
return http_error(StatusCode::SERVICE_UNAVAILABLE);
|
return http_error(StatusCode::SERVICE_UNAVAILABLE);
|
||||||
};
|
};
|
||||||
let backend = if let Some(be) = self.backends.get(server_name.as_str()) {
|
let backend = if let Some(be) = self.backends.apps.get(server_name.as_str()) {
|
||||||
be
|
be
|
||||||
|
} else if let Some(default_be) = &self.backends.default_app {
|
||||||
|
debug!("Serving by default app: {}", default_be);
|
||||||
|
self.backends.apps.get(default_be).unwrap()
|
||||||
} else {
|
} else {
|
||||||
return http_error(StatusCode::SERVICE_UNAVAILABLE);
|
return http_error(StatusCode::SERVICE_UNAVAILABLE);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
// use super::proxy_handler::handle_request;
|
// use super::proxy_handler::handle_request;
|
||||||
use crate::{backend::Backend, error::*, globals::Globals, log::*};
|
use crate::{backend::Backends, error::*, globals::Globals, log::*};
|
||||||
use hyper::{
|
use hyper::{
|
||||||
client::connect::Connect, server::conn::Http, service::service_fn, Body, Client, Request,
|
client::connect::Connect, server::conn::Http, service::service_fn, Body, Client, Request,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, net::SocketAddr, sync::Arc};
|
use std::{net::SocketAddr, sync::Arc};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncRead, AsyncWrite},
|
io::{AsyncRead, AsyncWrite},
|
||||||
net::TcpListener,
|
net::TcpListener,
|
||||||
|
|
@ -38,8 +38,8 @@ where
|
||||||
T: Connect + Clone + Sync + Send + 'static,
|
T: Connect + Clone + Sync + Send + 'static,
|
||||||
{
|
{
|
||||||
pub listening_on: SocketAddr,
|
pub listening_on: SocketAddr,
|
||||||
pub tls_enabled: bool, // TCP待受がTLSかどうか
|
pub tls_enabled: bool, // TCP待受がTLSかどうか
|
||||||
pub backends: Arc<HashMap<String, Backend>>, // TODO: hyper::uriで抜いたhostで引っ掛ける。Stringでいいのか?
|
pub backends: Arc<Backends>,
|
||||||
pub forwarder: Arc<Client<T>>,
|
pub forwarder: Arc<Client<T>>,
|
||||||
pub globals: Arc<Globals>,
|
pub globals: Arc<Globals>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ where
|
||||||
let cert_service = async {
|
let cert_service = async {
|
||||||
info!("Start cert watch service for {}", self.listening_on);
|
info!("Start cert watch service for {}", self.listening_on);
|
||||||
loop {
|
loop {
|
||||||
for (server_name, backend) in self.backends.iter() {
|
for (server_name, backend) in self.backends.apps.iter() {
|
||||||
if backend.tls_cert_key_path.is_some() && backend.tls_cert_path.is_some() {
|
if backend.tls_cert_key_path.is_some() && backend.tls_cert_path.is_some() {
|
||||||
if let Err(_e) = backend.update_server_config().await {
|
if let Err(_e) = backend.update_server_config().await {
|
||||||
warn!("Failed to update certs for {}", server_name);
|
warn!("Failed to update certs for {}", server_name);
|
||||||
|
|
@ -53,7 +53,7 @@ where
|
||||||
info!("No SNI in ClientHello");
|
info!("No SNI in ClientHello");
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let backend_serve = if let Some(backend_serve) = self.backends.get(svn){
|
let backend_serve = if let Some(backend_serve) = self.backends.apps.get(svn){
|
||||||
backend_serve
|
backend_serve
|
||||||
} else {
|
} else {
|
||||||
info!("No configuration for the server name {} given in client_hello", svn);
|
info!("No configuration for the server name {} given in client_hello", svn);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue