Ver código fonte

allow check ssh interval to be configurable. use constants for arg names.

master
Jonathan Cobb 4 anos atrás
pai
commit
e42fdd1188
3 arquivos alterados com 70 adições e 29 exclusões
  1. +7
    -3
      src/admin.rs
  2. +57
    -21
      src/main.rs
  3. +6
    -5
      src/ssh.rs

+ 7
- 3
src/admin.rs Ver arquivo

@@ -93,7 +93,8 @@ pub async fn start_admin (admin_reg : Arc<Mutex<Option<AdminRegistration>>>,
password_hash: String,
auth_token : Arc<String>,
ssh_priv_key : Arc<String>,
ssh_pub_key : Arc<String>) {
ssh_pub_key : Arc<String>,
check_ssh_interval : u64) {
let admin_sock : SocketAddr = format!("127.0.0.1:{}", admin_port).parse().unwrap();
let ssh_container: Arc<Mutex<SshContainer>> = Arc::new(Mutex::new(SshContainer::new()));

@@ -110,6 +111,7 @@ pub async fn start_admin (admin_reg : Arc<Mutex<Option<AdminRegistration>>>,
.and(warp::any().map(move || ssh_priv_key.clone()))
.and(warp::any().map(move || ssh_pub_key.clone()))
.and(warp::any().map(move || ssh_container_clone.clone()))
.and(warp::any().map(move || check_ssh_interval))
.and_then(handle_register));

let admin_reg_clone = admin_reg.clone();
@@ -137,7 +139,8 @@ async fn handle_register(registration : AdminRegistration,
auth_token : Arc<String>,
ssh_priv_key : Arc<String>,
ssh_pub_key : Arc<String>,
ssh_container : Arc<Mutex<SshContainer>>) -> Result<impl warp::Reply, warp::Rejection> {
ssh_container : Arc<Mutex<SshContainer>>,
check_ssh_interval : u64) -> Result<impl warp::Reply, warp::Rejection> {
// validate registration
let validated = validate_admin_registration(registration.clone());
if validated.is_err() {
@@ -221,7 +224,8 @@ async fn handle_register(registration : AdminRegistration,
internal_reg.bubble.clone(),
internal_reg.session.clone(),
reg_response.host_key,
ssh_priv_key).await;
ssh_priv_key,
check_ssh_interval).await;
if ssh_result.is_err() {
let err = ssh_result.err();
if err.is_none() {


+ 57
- 21
src/main.rs Ver arquivo

@@ -14,6 +14,7 @@ extern crate stderrlog;

extern crate rand;

use std::num::ParseIntError;
use std::path::Path;
use std::process::exit;
use std::sync::Arc;
@@ -36,71 +37,92 @@ use bubble_flexrouter::util::read_required_env_var_argument_as_file;
use bubble_flexrouter::util::read_path_to_string;
use bubble_flexrouter::version::VERSION;

const MIN_TOKEN_CHARS: usize = 50;
const MAX_TOKEN_CHARS: usize = 100;
const MIN_TOKEN_CHARS : usize = 50;
const MAX_TOKEN_CHARS : usize = 100;
const DEFAULT_CHECK_SSH_INTERVAL : u64 = 10;
const ARG_DNS1 : &'static str = "dns1";
const ARG_DNS2 : &'static str = "dns2";
const ARG_PROXY_PORT : &'static str = "proxy_port";
const ARG_ADMIN_PORT : &'static str = "admin_port";
const ARG_PASSWORD_FILE : &'static str = "password_file";
const ARG_PASSWORD_ENV_VAR : &'static str = "password_env_var";
const ARG_TOKEN_FILE : &'static str = "token_file";
const ARG_SSH_KEY_FILE : &'static str = "ssh_key_file";
const ARG_CHECK_SSH_INTERVAL : &'static str = "check_ssh_interval";
const ARG_LOG_LEVEL : &'static str = "log_level";

#[tokio::main]
async fn main() {
let default_check_ssh_interval_string = DEFAULT_CHECK_SSH_INTERVAL.to_string();
let default_check_ssh_interval = default_check_ssh_interval_string.as_str();

let args : ArgMatches = App::new("bubble-flexrouter")
.version(VERSION)
.author("Jonathan Cobb <jonathan@getbubblenow.com>")
.about("Proxy services for Bubble nodes")
.arg(Arg::with_name("dns1")
.arg(Arg::with_name(ARG_DNS1)
.short("d")
.long("dns1")
.value_name("IP_ADDRESS")
.help("Primary DNS server")
.default_value("1.1.1.1")
.takes_value(true))
.arg(Arg::with_name("dns2")
.arg(Arg::with_name(ARG_DNS2)
.short("e")
.long("dns2")
.value_name("IP_ADDRESS")
.help("Secondary DNS server")
.default_value("1.0.0.1")
.takes_value(true))
.arg(Arg::with_name("proxy_port")
.arg(Arg::with_name(ARG_PROXY_PORT)
.short("p")
.long("proxy-port")
.value_name("PORT")
.help("port to listen for proxy connections")
.default_value("9823")
.takes_value(true))
.arg(Arg::with_name("admin_port")
.arg(Arg::with_name(ARG_ADMIN_PORT)
.short("a")
.long("admin-port")
.value_name("PORT")
.help("port to listen for admin connections")
.default_value("9833")
.takes_value(true))
.arg(Arg::with_name("password_file")
.arg(Arg::with_name(ARG_PASSWORD_FILE)
.short("w")
.long("password-file")
.value_name("ENV_VAR_NAME")
.help("environment variable naming the file that contains bcrypt-hashed password required for admin commands")
.default_value("BUBBLE_FR_PASS")
.takes_value(true))
.arg(Arg::with_name("password_env_var")
.arg(Arg::with_name(ARG_PASSWORD_ENV_VAR)
.short("W")
.long("password-env-var")
.value_name("ENV_VAR_NAME")
.help("environment variable containing the admin password. overwrites previous value")
.takes_value(true))
.arg(Arg::with_name("token_file")
.arg(Arg::with_name(ARG_TOKEN_FILE)
.short("t")
.long("token-file")
.value_name("ENV_VAR_NAME")
.help("environment variable naming the file that contains the bubble token")
.default_value("BUBBLE_FR_TOKEN")
.takes_value(true))
.arg(Arg::with_name("ssh_key_file")
.arg(Arg::with_name(ARG_SSH_KEY_FILE)
.short("s")
.long("ssh-key-file")
.value_name("ENV_VAR_NAME")
.help("environment variable naming the file that contains the SSH key")
.default_value("BUBBLE_FR_SSH_KEY")
.takes_value(true))
.arg(Arg::with_name("log_level")
.arg(Arg::with_name(ARG_CHECK_SSH_INTERVAL)
.short("c")
.long("check-ssh-interval")
.value_name("SECONDS")
.help("how often to verify that the SSH tunnel is OK")
.default_value(default_check_ssh_interval)
.takes_value(true))
.arg(Arg::with_name(ARG_LOG_LEVEL)
.short("v")
.long("log-level")
.value_name("LOG_LEVEL")
@@ -109,7 +131,7 @@ async fn main() {
.takes_value(true))
.get_matches();

let (verbosity, quiet) = match args.value_of("log_level").unwrap().to_ascii_lowercase().as_str() {
let (verbosity, quiet) = match args.value_of(ARG_LOG_LEVEL).unwrap().to_ascii_lowercase().as_str() {
"off" => (0, true),
"error" => (0, false),
"warn" => (1, false),
@@ -130,18 +152,18 @@ async fn main() {
// todo: ensure we are running as root (or Administrator on Windows)
info!("The current user is {}", whoami::username());

let password_file_env_var_opt = args.value_of("password_file");
let password_file_env_var_opt = args.value_of(ARG_PASSWORD_FILE);
let password_file = read_required_env_var_argument("password-file", password_file_env_var_opt);

let password_opt = args.value_of("password_env_var");
let password_opt = args.value_of(ARG_PASSWORD_ENV_VAR);
let password_hash = init_password(password_file.as_str(), password_opt);

let admin_port = args.value_of("admin_port").unwrap().parse::<u16>().unwrap();
let dns1_ip = args.value_of("dns1").unwrap();
let dns2_ip = args.value_of("dns2").unwrap();
let proxy_port = args.value_of("proxy_port").unwrap().parse::<u16>().unwrap();
let admin_port = args.value_of(ARG_ADMIN_PORT).unwrap().parse::<u16>().unwrap();
let dns1_ip = args.value_of(ARG_DNS1).unwrap();
let dns2_ip = args.value_of(ARG_DNS2).unwrap();
let proxy_port = args.value_of(ARG_PROXY_PORT).unwrap().parse::<u16>().unwrap();

let ssh_key_file_env_var_opt = args.value_of("ssh_key_file");
let ssh_key_file_env_var_opt = args.value_of(ARG_SSH_KEY_FILE);
let ssh_key_path_path_string = read_required_env_var_argument("ssh-key-file", ssh_key_file_env_var_opt);
let ssh_priv_key = Arc::new(ssh_key_path_path_string);
let ssh_priv_clone = ssh_priv_key.clone();
@@ -155,7 +177,7 @@ async fn main() {
let ssh_pub_key_path = Path::new(ssh_pub_key_path_name.as_str());
let ssh_pub_key = Arc::new(read_path_to_string(ssh_pub_key_path));

let token_file_env_var_opt = args.value_of("token_file");
let token_file_env_var_opt = args.value_of(ARG_TOKEN_FILE);
let auth_token_string = read_required_env_var_argument_as_file("token-file", token_file_env_var_opt);
let auth_token_val = auth_token_string.trim();
if auth_token_val.len() < MIN_TOKEN_CHARS {
@@ -168,6 +190,19 @@ async fn main() {
}
let auth_token = Arc::new(String::from(auth_token_val));

let check_ssh_interval_opt = args.value_of(ARG_CHECK_SSH_INTERVAL);
if check_ssh_interval_opt.is_none() {
error!("main: check ssh interval was not set");
exit(2);
}
let check_ssh_interval_val = check_ssh_interval_opt.unwrap();
let check_ssh_interval_result: Result<u64, ParseIntError> = check_ssh_interval_val.trim().parse();
if check_ssh_interval_result.is_err() {
error!("main: check ssh interval was not a valid integer: {}", check_ssh_interval_val);
exit(2);
}
let check_ssh_interval = check_ssh_interval_result.unwrap();

let admin_reg: Arc<Mutex<Option<AdminRegistration>>> = Arc::new(Mutex::new(None));

let admin = start_admin(
@@ -177,7 +212,8 @@ async fn main() {
password_hash,
auth_token.clone(),
ssh_priv_key.clone(),
ssh_pub_key.clone()
ssh_pub_key.clone(),
check_ssh_interval
);
let proxy = start_proxy(
dns1_ip,


+ 6
- 5
src/ssh.rs Ver arquivo

@@ -79,7 +79,8 @@ pub async fn spawn_ssh (ssh_container : Arc<Mutex<SshContainer>>,
bubble : Arc<String>,
session : Arc<String>,
host_key : String,
priv_key : Arc<String>) -> Result<bool, Option<Error>> {
priv_key : Arc<String>,
check_ssh_interval : u64) -> Result<bool, Option<Error>> {
let mut guard = ssh_container.lock().await;
if (*guard).child.is_some() {
info!("spawn_ssh: ssh tunnel exists, not respawning");
@@ -120,7 +121,7 @@ pub async fn spawn_ssh (ssh_container : Arc<Mutex<SshContainer>>,
let check_ip = ip.clone();
let check_session = session.clone();
trace!("spawn_ssh: starting abortable checker");
let task = tokio::spawn(check_ssh(ssh_container.clone(), check_host, check_ip, check_session));
let task = tokio::spawn(check_ssh(ssh_container.clone(), check_host, check_ip, check_session, check_ssh_interval));
let (_fut, abort_handle) = abortable(task);
(*guard).checker_abort_handle = Some(Arc::new(Mutex::new(abort_handle)));
Ok(true)
@@ -218,15 +219,15 @@ fn build_ssh_command<'a>(command : &mut Command, tunnel: String, target: String,
}

const CHECK_SSH_START_DELAY : u64 = 10;
const CHECK_SSH_INTERVAL: u64 = 10;
const MAX_CHECK_ERRORS_BEFORE_RESTART : u8 = 3;
const CHECK_SSH_HTTP_TIMEOUT: u64 = 10;

async fn check_ssh (ssh_container : Arc<Mutex<SshContainer>>,
bubble : Arc<String>,
ip : Arc<String>,
session : Arc<String>) -> bool {
let mut checker = interval_at(Instant::now().checked_add(Duration::new(CHECK_SSH_START_DELAY, 0)).unwrap(), Duration::new(CHECK_SSH_INTERVAL, 0));
session : Arc<String>,
check_ssh_interval : u64) -> bool {
let mut checker = interval_at(Instant::now().checked_add(Duration::new(CHECK_SSH_START_DELAY, 0)).unwrap(), Duration::new(check_ssh_interval, 0));
let check_url = format!("https://{}/api/me/flexRouters/{}/status", bubble.clone(), ip.clone());
let mut headers = HeaderMap::new();
headers.insert(HEADER_BUBBLE_SESSION, HeaderValue::from_str(session.to_string().as_str()).unwrap());


Carregando…
Cancelar
Salvar