#![warn(rust_2018_idioms)]
#![warn(clippy::all)]
pub mod auth;
pub mod buffer_pool;
pub mod config;
pub mod connection;
pub mod copy_pump;
pub mod handshake;
pub mod helpers;
pub mod request;
use tokio::net::TcpListener;
use tracing::{info, warn};
use crate::buffer_pool::BufferPool;
use crate::config::Config;
use crate::connection::Connection;
use crate::helpers::{Helpers, Res};
pub async fn run(config: Config) -> Res<()> {
let listen_ip = config.listen_ip()?;
let auth_enabled = config.credentials()?.is_some();
info!("Version: {}", env!("CARGO_PKG_VERSION"));
info!("Listen IP: {}", listen_ip);
info!("Endpoint IP: {}", config.endpoint_ip()?);
info!("Port: {}", config.port);
info!("Buffer Size: {}", config.buffer_size);
info!("Read Timeout: {}", config.read_timeout);
info!("Accept CIDR: {}", config.accept_cidr);
info!("Auth: {}", if auth_enabled { "user/pass" } else { "none" });
let listener = TcpListener::bind(format!("{}:{}", listen_ip, config.port)).await?;
info!("Listening on tcp://{}:{} ...", listen_ip, config.port);
serve(listener, config).await
}
pub async fn serve(listener: TcpListener, config: Config) -> Res<()> {
let endpoint_ip = config.endpoint_ip()?;
let cidr = Helpers::parse_cidr(&config.accept_cidr)?;
let cidr_is_trivial = cidr.is_trivial();
let credentials = config.credentials()?;
let mut pool = BufferPool::new(2 * config.buffer_size);
loop {
let (stream, _) = listener.accept().await?;
let remote_ip = stream.peer_addr()?.ip();
if !cidr_is_trivial && !Helpers::is_ip_in_cidr(&remote_ip, &cidr)? {
warn!("Request from {} does not match {}: dropping connection.", remote_ip, config.accept_cidr);
drop(stream);
continue;
}
Connection::from(stream, endpoint_ip.clone(), pool.lease(), config.read_timeout, credentials.clone()).handle();
}
}