#![recursion_limit="512"]
#![warn(rust_2018_idioms)]
#[cfg(tcp)]
#[cfg(udp)]
use std::sync::Arc;
use chrono::Local;
use std::path::PathBuf;
use std::path::Path;
use log::*;
use argh::FromArgs;
use log4rs;
mod tcp;
mod udp;
mod dns;
use rproxy::Proxy;
#[allow(dead_code)]
#[derive(FromArgs)]
#[argh(description = "rproxy is a platform independent UDP TCP high performance async proxy")]
struct Options {
#[argh(option, short='r', default="\"\".to_string()")]
remote: String,
#[argh(option, short='b', default="\"\".to_string()")]
bind: String,
#[argh(option, short='p', default="\"UDP\".to_string()")]
protocol: String,
#[argh(switch, short='d')]
debug: bool,
#[argh(option, short = 'l', default = "\"rproxy.logger.yaml\".to_string()")]
logger_settings: String,
#[argh(option, short = 'c')]
config: Option<PathBuf>,
}
static MY_LOGGER: MyLogger = MyLogger;
struct MyLogger;
impl log::Log for MyLogger {
fn enabled(&self, _metadata: &Metadata<'_>) -> bool {
true
}
fn log(&self, record: &Record<'_>) {
if self.enabled(record.metadata()) {
println!("[{}][{}] - {}", record.level(), Local::now(), record.args());
}
}
fn flush(&self) {}
}
#[tokio::main]
async fn main(){
let options: Options = argh::from_env();
if Path::new(&options.logger_settings).exists(){
log4rs::init_file(&options.logger_settings,
Default::default()).unwrap();
debug!("NICE");
} else {
log::set_logger(&MY_LOGGER).unwrap();
if options.debug {
log::set_max_level(LevelFilter::Debug);
} else {
log::set_max_level(LevelFilter::Info);
}
}
match options.config {
None => {
if options.protocol == "UDP"{
udp::udp_proxy(&options.bind, &options.remote).await.unwrap();
} else if options.protocol == "TCP" {
tcp::tcp_proxy(&options.bind, &options.remote).await.unwrap();
}
},
Some(_config) => {
if _config.as_path().exists() {
if let Ok(_path) = _config.to_owned().into_os_string().into_string(){
let content = std::fs::read_to_string(_path).unwrap();
match serde_json::from_str::<Vec<Proxy>>(content.as_str()){
Ok(proxies) => {
let mut procs = vec![];
for i in 0..proxies.len() {
let bind = proxies[i].bind.to_owned();
let remote = proxies[i].remote.to_owned();
if proxies[i].protocol == "UDP"{
procs.push(tokio::spawn(async move {udp::udp_proxy(&bind, &remote).await}))
} else if proxies[i].protocol == "TCP" {
procs.push(tokio::spawn(async move {tcp::tcp_proxy(&bind, &remote).await}))
}
}
futures::future::join_all(procs).await;
},
Err(e) => {
error!("Failed to parse configuration json {:?}", e);
}
}
}
} else {
error!("Invalid configuration file path {}", _config.as_path().display());
}
}
}
}