diff --git a/Cargo.lock b/Cargo.lock index 72d2a2be9..7e1ff1fe5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -432,7 +432,7 @@ dependencies = [ name = "althea_rs" version = "0.1.11" dependencies = [ - "rita", + "rita_bin", ] [[package]] @@ -529,16 +529,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "assert-json-diff" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f1c3703dd33532d7f0ca049168930e9099ecac238e23cf932f3a69c42f06da" -dependencies = [ - "serde 1.0.126", - "serde_json", -] - [[package]] name = "atty" version = "0.2.14" @@ -891,17 +881,6 @@ dependencies = [ "sodiumoxide", ] -[[package]] -name = "colored" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" -dependencies = [ - "atty", - "lazy_static", - "winapi 0.3.9", -] - [[package]] name = "compressed_log" version = "0.3.8" @@ -1126,12 +1105,6 @@ dependencies = [ "syn 1.0.73", ] -[[package]] -name = "difference" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" - [[package]] name = "digest" version = "0.8.1" @@ -2204,12 +2177,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "minihttpse" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e50e8cee436b4318ec759930d6ea5f839d14dab94e81b6fba37d492d07ebf55" - [[package]] name = "miniz_oxide" version = "0.4.4" @@ -2284,30 +2251,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "mockito" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d10030163d67f681db11810bc486df3149e6d91c8b4f3f96fa8b62b546c2cef8" -dependencies = [ - "assert-json-diff 2.0.1", - "colored", - "difference", - "httparse", - "lazy_static", - "log", - "rand 0.8.4", - "regex", - "serde_json", - "serde_urlencoded 0.7.0", -] - -[[package]] -name = "mockstream" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bbe0c0c9d254b463b13734bc361d1423289547e052b1e77e5a77292496ba2e" - [[package]] name = "native-tls" version = "0.2.7" @@ -3223,7 +3166,7 @@ dependencies = [ ] [[package]] -name = "rita" +name = "rita_bin" version = "0.18.0" dependencies = [ "actix 0.11.1", @@ -3236,44 +3179,58 @@ dependencies = [ "althea_types", "antenna_forwarding_client", "arrayvec 0.7.1", - "auto-bridge", - "babel_monitor", - "babel_monitor_legacy", - "byteorder", - "bytes 1.0.1", - "clarity", "clu", "compressed_log", - "config", "diesel", "docopt", - "dotenv", "env_logger", - "exit_db", "failure", "flate2", - "futures 0.1.31", - "futures 0.3.15", - "handlebars", "hex-literal", - "ipnetwork 0.14.0", "jemallocator", "lazy_static", - "lettre", - "lettre_email", "log", - "minihttpse", - "mockito", - "mockstream", - "num-traits 0.2.14", - "num256", "openssl", "openssl-probe", "phonenumber", "r2d2", - "rand 0.8.4", "regex", "reqwest", + "rita_client", + "rita_common", + "rita_exit", + "rita_tower", + "serde 1.0.126", + "serde_derive", + "serde_json", + "settings", +] + +[[package]] +name = "rita_client" +version = "0.18.0" +dependencies = [ + "actix 0.7.11", + "actix-web 0.7.19", + "althea_kernel_interface", + "althea_types", + "arrayvec 0.7.1", + "babel_monitor", + "babel_monitor_legacy", + "clarity", + "clu", + "compressed_log", + "failure", + "futures 0.1.31", + "hex-literal", + "lazy_static", + "lettre", + "lettre_email", + "log", + "num-traits 0.2.14", + "num256", + "phonenumber", + "rita_common", "serde 1.0.126", "serde_derive", "serde_json", @@ -3283,11 +3240,96 @@ dependencies = [ "tokio 0.1.22", "tokio-codec", "tokio-io", - "trust-dns-resolver", + "web30 0.4.3", +] + +[[package]] +name = "rita_common" +version = "0.18.0" +dependencies = [ + "actix 0.11.1", + "actix 0.7.11", + "actix-web 0.7.19", + "actix-web-httpauth", + "althea_kernel_interface", + "althea_types", + "antenna_forwarding_client", + "arrayvec 0.7.1", + "auto-bridge", + "babel_monitor", + "babel_monitor_legacy", + "byteorder", + "bytes 1.0.1", + "clarity", + "docopt", + "failure", + "flate2", + "futures 0.1.31", + "futures 0.3.15", + "hex-literal", + "ipnetwork 0.14.0", + "lazy_static", + "log", + "num-traits 0.2.14", + "num256", + "rand 0.8.4", + "serde 1.0.126", + "serde_derive", + "serde_json", + "settings", + "tokio 0.1.22", "web30 0.14.6", "web30 0.4.3", ] +[[package]] +name = "rita_exit" +version = "0.18.0" +dependencies = [ + "actix 0.7.11", + "actix-web 0.7.19", + "actix-web-httpauth", + "althea_kernel_interface", + "althea_types", + "arrayvec 0.7.1", + "babel_monitor", + "babel_monitor_legacy", + "compressed_log", + "diesel", + "exit_db", + "failure", + "futures 0.1.31", + "handlebars", + "ipnetwork 0.14.0", + "lazy_static", + "lettre", + "lettre_email", + "log", + "num256", + "phonenumber", + "r2d2", + "rand 0.8.4", + "reqwest", + "rita_common", + "serde 1.0.126", + "serde_derive", + "serde_json", + "settings", + "sodiumoxide", +] + +[[package]] +name = "rita_tower" +version = "0.18.0" +dependencies = [ + "althea_types", + "lazy_static", + "log", + "serde 1.0.126", + "serde_derive", + "serde_json", +] + [[package]] name = "rust-ini" version = "0.13.0" @@ -4530,7 +4572,7 @@ source = "git+https://github.com/althea-net/web30?rev=a600b8b8ebf2c49badee6b65ac dependencies = [ "actix 0.7.11", "actix-web 0.7.19", - "assert-json-diff 1.1.0", + "assert-json-diff", "bytes 1.0.1", "clarity", "failure", diff --git a/Cargo.toml b/Cargo.toml index 9c234100d..e8c1e747a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,17 +5,17 @@ authors = ["Stan Drozd "] edition = "2018" [features] -development = ["rita/development"] -dash_debug = ["rita/dash_debug"] -server = ["rita/server"] -bundle_openssl = ["rita/bundle_openssl"] -jemalloc = ["rita/jemalloc"] +development = ["rita_bin/development"] +dash_debug = ["rita_bin/dash_debug"] +server = ["rita_bin/server"] +bundle_openssl = ["rita_bin/bundle_openssl"] +jemalloc = ["rita_bin/jemalloc"] [dependencies] -rita = { path = "./rita" } +rita_bin = { path = "./rita_bin" } [workspace] -members = ["althea_kernel_interface", "settings", "clu", "exit_db", "antenna_forwarding_client", "antenna_forwarding_protocol", "auto_bridge", "babel_monitor_legacy"] +members = ["althea_kernel_interface", "settings", "clu", "exit_db", "antenna_forwarding_client", "antenna_forwarding_protocol", "auto_bridge", "babel_monitor_legacy","rita_common","rita_exit","rita_tower","rita_client"] [profile.release] opt-level = "z" diff --git a/althea_kernel_interface/src/hardware_info.rs b/althea_kernel_interface/src/hardware_info.rs index dd1846fa1..76f788378 100644 --- a/althea_kernel_interface/src/hardware_info.rs +++ b/althea_kernel_interface/src/hardware_info.rs @@ -30,8 +30,10 @@ pub fn get_hardware_info(device_name: Option) -> Result) -> Result Result { let sys_kernel_ver_error = Err(Error::FailedToGetSystemKernelVersion); diff --git a/clu/src/lib.rs b/clu/src/lib.rs index 95d87cb96..89dae75d6 100644 --- a/clu/src/lib.rs +++ b/clu/src/lib.rs @@ -13,14 +13,13 @@ use failure::Error; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; use regex::Regex; -use settings::exit::RitaExitSettings; -use settings::RitaCommonSettings; +use settings::client::RitaClientSettings; +use settings::exit::RitaExitSettingsStruct; use std::fs::File; use std::io::Read; use std::net::IpAddr; use std::path::Path; use std::str; -use std::sync::{Arc, RwLock}; #[derive(Debug, Fail)] pub enum CluError { @@ -68,13 +67,14 @@ pub fn cleanup() -> Result<(), Error> { Ok(()) } -fn linux_init(config: Arc>) -> Result<(), Error> { +fn linux_init(settings: RitaClientSettings) -> Result { cleanup()?; + let mut settings = settings; + let mut network_settings = settings.network; // this value will be none for most routers but a route for gateways. - KI.restore_default_route(&mut config.get_network_mut().last_default_route)?; + KI.restore_default_route(&mut network_settings.last_default_route)?; // handle things we need to generate at runtime - let mut network_settings = config.get_network_mut(); let mesh_ip_option = network_settings.mesh_ip; let wg_pubkey_option = network_settings.wg_public_key; let wg_privkey_option = network_settings.wg_private_key; @@ -161,11 +161,9 @@ fn linux_init(config: Arc>) -> Resu warn!("Duplicate interface removed!"); } } + settings.network = network_settings; - // Yield the mut lock - drop(network_settings); - - let mut payment_settings = config.get_payment_mut(); + let mut payment_settings = settings.payment; let eth_private_key_option = payment_settings.eth_private_key; match eth_private_key_option { @@ -187,20 +185,19 @@ fn linux_init(config: Arc>) -> Resu } } - Ok(()) + settings.payment = payment_settings; + + trace!("Starting with settings (after clu) : {:?}", settings); + assert!(settings.get_identity().is_some()); + Ok(settings) } -fn linux_exit_init( - config: Arc>, -) -> Result<(), Error> { +fn linux_exit_init(settings: RitaExitSettingsStruct) -> Result { cleanup()?; + let mut settings = settings; - // we need to avoid a deadlock by copying things out explicitly - let exit_network_settings_ref = config.get_exit_network(); - let exit_network_settings = exit_network_settings_ref.clone(); - drop(exit_network_settings_ref); - - let mut network_settings = config.get_network_mut(); + let mut network_settings = settings.network; + let exit_network_settings = settings.exit_network; let mesh_ip_option = network_settings.mesh_ip; let wg_pubkey_option = network_settings.wg_public_key; let wg_privkey_option = network_settings.wg_private_key; @@ -246,9 +243,7 @@ fn linux_exit_init( &exit_network_settings.wg_private_key.clone(), )?; - drop(network_settings); - - let mut payment_settings = config.get_payment_mut(); + let mut payment_settings = settings.payment; let eth_private_key_option = payment_settings.eth_private_key; match eth_private_key_option { @@ -269,30 +264,26 @@ fn linux_exit_init( payment_settings.eth_address = Some(new_private_key.to_public_key()?) } } - - Ok(()) + settings.payment = payment_settings; + settings.network = network_settings; + settings.exit_network = exit_network_settings; + trace!("Starting with settings (after clu) : {:?}", settings); + assert!(settings.get_identity().is_some()); + Ok(settings) } -pub fn init(platform: &str, settings: Arc>) { +pub fn init(platform: &str, settings: RitaClientSettings) -> RitaClientSettings { match platform { - "linux" => linux_init(settings.clone()).unwrap(), + "linux" => linux_init(settings).unwrap(), _ => unimplemented!(), } - trace!( - "Starting with settings (after clu) : {:?}", - settings.read().unwrap() - ); } -pub fn exit_init(platform: &str, settings: Arc>) { +pub fn exit_init(platform: &str, settings: RitaExitSettingsStruct) -> RitaExitSettingsStruct { match platform { - "linux" => linux_exit_init(settings.clone()).unwrap(), + "linux" => linux_exit_init(settings).unwrap(), _ => unimplemented!(), } - trace!( - "Starting with settings (after clu) : {:?}", - settings.read().unwrap() - ); } #[cfg(test)] diff --git a/integration-tests/readme.md b/integration-tests/readme.md index 45172a409..6fc8a0983 100644 --- a/integration-tests/readme.md +++ b/integration-tests/readme.md @@ -21,6 +21,8 @@ althea-mesh/ |- babeld/ # Althea fork of babeld ``` +## To run locally + Network lab needs to be installed using `bpkg`. Example: @@ -34,23 +36,46 @@ bpkg install sudomesh/network-lab bash rita.sh ``` +## To run in Docker + +**The Docker version of this test _only_ tests files that are in git commits not changes in your working directory** + +Example: +``` +sudo modprobe wireguard # only needs to be run once on system reboot +bash scrips/test.sh +``` -Running Docker to check logs: +### Checking docker container logs -Docker is useful when encountering errors when running integration tests. These error messages are usually not very descriptive, so to view the backtrace and +Logging into the docker container is useful when encountering errors when running integration tests. These error messages are usually not very descriptive, so to view the backtrace and debugging lines (for instance 'info!' macro), we can view log files of rita instances, which we can access with docker container. Get docker running by following the instructions below. -run the test using the command - bash scripts/test.sh -once you have the test env running, open a new terminal and run: - docker exec -it rita-test /bin/bash -once you are in the docker, navigate to - althea_rs/integration-tests +``` +# run the test using the command +bash scripts/test.sh +# once you have the test env running, open a new terminal and run: +docker exec -it rita-test /bin/bash +# once you are in the docker, navigate to +althea_rs/integration-tests +``` wait for the error and then check this directory for corresponding logs messages. -log files are of the format rita-n*.log +log files are of the format rita-n\*.log When adding more info! macro debugging lines, make sure to commit these changes to see these in the logs. +### Observing net namespaces + +This test uses net namespaces, these are conceptually similar to containers. A linux container is running on the same kernel as the host machine, but with a large number of changed +namespace variables. This is how container isolation is performed. Net namespaces are a way to use only the network routing table isolation part of the container system. For this test +we have a docker container (it's own net namespace, process namespace, filesystem namespace etc) that contains within it several more net namespaces. This separation allows us to run many +instances of Rita, each of which interact with and make significant adjustments to the routing table, without needing heavy duty virtual machiens for our tests. +Now that we have the theory out of the way, the real question you want to ask is "how do I run a simple command like `wg` and see the Wireguard tunnels for a particular virtual rita router?" + +``` +sudo ip netns exec netlab-5 wg +``` +When run inside the container, or natively if you are running natively, this will run the command `wg` in the network namespace of rita-n5 instance diff --git a/rita/.env b/rita/.env deleted file mode 100644 index 186be7cea..000000000 --- a/rita/.env +++ /dev/null @@ -1 +0,0 @@ -DATABASE_URL=test.db diff --git a/rita/.vscode/settings.json b/rita/.vscode/settings.json deleted file mode 100644 index 7a73a41bf..000000000 --- a/rita/.vscode/settings.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} \ No newline at end of file diff --git a/rita/src/exit.rs b/rita/src/exit.rs deleted file mode 100644 index 14222de11..000000000 --- a/rita/src/exit.rs +++ /dev/null @@ -1,315 +0,0 @@ -//! This is the main source file for the Rita exit binary, by 'exit' we mean 'a vpn server, not a -//! mesh router out in the field'. -//! -//! All meshing and billing functionality is contained in `rita_common` and is common to both rita and -//! `rita_exit`. The major difference is billing and connection code for the 'exit', the mandatory -//! vpn system integrated into the Althea network design, as well as API endpoints for a management -//! dashboard of router functions like wifi, which the exit is not expected to have. -//! -//! This file initializes the dashboard endpoints for the exit as well as the common and exit -//! specific actors. - -#![warn(clippy::all)] -#![allow(clippy::pedantic)] -#![forbid(unsafe_code)] - -#[cfg(feature = "jemalloc")] -use jemallocator::Jemalloc; -#[cfg(feature = "jemalloc")] -#[global_allocator] -static GLOBAL: Jemalloc = Jemalloc; - -#[macro_use] -extern crate failure; -#[macro_use] -extern crate lazy_static; -#[macro_use] -extern crate log; -#[macro_use] -extern crate serde_derive; -#[macro_use] -extern crate serde_json; -extern crate phonenumber; - -use actix_web::http::Method; -use actix_web::{http, server, App}; -use althea_types::SystemChain; -use althea_types::WgKey; -use diesel::r2d2::ConnectionManager; -use diesel::PgConnection; -use docopt::Docopt; -use r2d2::Pool; -use settings::exit::ExitNetworkSettings; -use settings::exit::ExitVerifSettings; -use std::collections::HashSet; -use std::sync::{Arc, RwLock}; -use std::time::Instant; - -#[cfg(test)] -use std::sync::Mutex; - -use settings::exit::{RitaExitSettings, RitaExitSettingsStruct}; -use settings::RitaCommonSettings; - -#[cfg(not(test))] -use settings::FileWrite; - -mod middleware; -mod rita_common; -mod rita_exit; - -use crate::rita_common::dashboard::own_info::READABLE_VERSION; -use crate::rita_common::utils::env_vars_contains; -use crate::rita_exit::database::sms::send_admin_notification_sms; -use rita_common::rita_loop::check_rita_common_actors; -use rita_common::rita_loop::start_core_rita_endpoints; -use rita_exit::rita_loop::start_rita_exit_endpoints; -use rita_exit::rita_loop::start_rita_exit_loop; -use rita_exit::{enable_remote_logging, rita_loop::check_rita_exit_actors}; - -use crate::rita_common::dashboard::babel::*; -use crate::rita_common::dashboard::debts::*; -use crate::rita_common::dashboard::development::*; -use crate::rita_common::dashboard::nickname::*; -use crate::rita_common::dashboard::own_info::*; -use crate::rita_common::dashboard::settings::*; -use crate::rita_common::dashboard::token_bridge::*; -use crate::rita_common::dashboard::usage::*; -use crate::rita_common::dashboard::wallet::*; -use crate::rita_common::dashboard::wg_key::*; -use crate::rita_common::network_endpoints::*; -use crate::rita_exit::network_endpoints::*; - -#[derive(Debug, Deserialize, Default)] -pub struct Args { - flag_config: String, - flag_future: bool, -} - -lazy_static! { - static ref USAGE: String = format!( - "Usage: rita_exit --config= -Options: - -c, --config= Name of config file - --future Enable B side of A/B releases -About: - Version {} - {} - git hash {}", - READABLE_VERSION, - env!("CARGO_PKG_VERSION"), - env!("GIT_HASH") - ); -} - -use althea_kernel_interface::KernelInterface; - -#[cfg(not(test))] -use althea_kernel_interface::LinuxCommandRunner; -#[cfg(test)] -use althea_kernel_interface::TestCommandRunner; - -#[cfg(test)] -lazy_static! { - pub static ref KI: Box = Box::new(TestCommandRunner { - run_command: Arc::new(Mutex::new(Box::new(|_program, _args| { - panic!("kernel interface used before initialized"); - }))) - }); -} - -#[cfg(test)] -lazy_static! { - pub static ref ARGS: Args = Args::default(); -} - -#[cfg(not(test))] -lazy_static! { - pub static ref KI: Box = Box::new(LinuxCommandRunner {}); -} - -#[cfg(not(test))] -lazy_static! { - pub static ref ARGS: Args = Docopt::new((*USAGE).as_str()) - .and_then(|d| d.deserialize()) - .unwrap_or_else(|e| e.exit()); -} - -// These are a set of vars that are never updated during runtime. This means we can have -// read only versions of them available here to prevent lock contention on large exits. -// this is probably an overengineered optimization that can be safely removed -lazy_static! { - pub static ref EXIT_WG_PRIVATE_KEY: WgKey = SETTING.get_exit_network().wg_private_key; -} -lazy_static! { - pub static ref EXIT_VERIF_SETTINGS: Option = SETTING.get_verif_settings(); -} -// this value is actually updated so that exit prices can be changed live and we can hit the read -// only lock the vast majority of the time. -lazy_static! { - pub static ref EXIT_NETWORK_SETTINGS: ExitNetworkSettings = SETTING.get_exit_network().clone(); -} -lazy_static! { - pub static ref EXIT_SYSTEM_CHAIN: SystemChain = SETTING.get_payment().system_chain; -} -lazy_static! { - pub static ref EXIT_DESCRIPTION: String = SETTING.get_description(); -} -lazy_static! { - pub static ref EXIT_ALLOWED_COUNTRIES: HashSet = - SETTING.get_allowed_countries().clone(); -} -// price is updated at runtime, but we only want to grab a read lock to update it every few seconds -// since this is done cooperatively in get_exit_info() only one read lock is aquired but we can -// still update it every UPDATE_INTERVAL seconds -// in the format price/last updated time -lazy_static! { - pub static ref EXIT_PRICE: Arc> = Arc::new(RwLock::new(( - SETTING.get_exit_network().exit_price, - Instant::now() - ))); -} - -lazy_static! { - pub static ref DB_POOL: Arc>>> = { - let db_uri = SETTING.get_db_uri(); - - if !(db_uri.contains("postgres://") - || db_uri.contains("postgresql://") - || db_uri.contains("psql://")) - { - panic!("You must provide a valid postgressql database uri!"); - } - - let manager = ConnectionManager::new(SETTING.get_db_uri()); - Arc::new(RwLock::new( - r2d2::Pool::builder() - .max_size(SETTING.get_workers() + 1) - .build(manager) - .expect("Failed to create pool."), - )) - }; -} - -#[cfg(not(test))] -lazy_static! { - pub static ref SETTING: Arc> = { - let settings_file = &ARGS.flag_config; - - let s = RitaExitSettingsStruct::new_watched(settings_file).unwrap(); - - s.set_future(ARGS.flag_future); - - clu::exit_init("linux", s.clone()); - - s.read().unwrap().write(settings_file).unwrap(); - - s - }; -} - -#[cfg(test)] -lazy_static! { - pub static ref SETTING: Arc> = - Arc::new(RwLock::new(RitaExitSettingsStruct::test_default())); -} - -/// used to crash the exit on first startup if config does not make sense -/// as is usually desirable for cloud infrastruture -fn sanity_check_config() { - if !SETTING.get_allowed_countries().is_empty() - && SETTING.get_exit_network().geoip_api_key.is_none() - { - panic!("GEOIP enforcement configured but not api key provided!"); - } -} - -fn main() { - // On Linux static builds we need to probe ssl certs path to be able to - // do TLS stuff. - openssl_probe::init_ssl_cert_env_vars(); - - // An exit setting dictating if this exit operator wants to log remotely or locally - let should_remote_log = SETTING.get_remote_log(); - // if remote logging is disabled, or the NO_REMOTE_LOG env var is set we should use the - // local logger and log to std-out. Note we don't care what is actually set in NO_REMOTE_LOG - // just that it is set - if !should_remote_log || env_vars_contains("NO_REMOTE_LOG") { - env_logger::init(); - } else { - let res = enable_remote_logging(); - println!("logging status {:?}", res); - } - - if cfg!(feature = "development") { - println!("Warning!"); - println!("This build is meant only for development purposes."); - println!("Running this on production as an exit node is unsupported and not safe!"); - } - - let args: Args = Docopt::new((*USAGE).as_str()) - .and_then(|d| d.deserialize()) - .unwrap_or_else(|e| e.exit()); - - let settings_file = args.flag_config; - - // to get errors before lazy static - RitaExitSettingsStruct::new(&settings_file).expect("Settings parse failure"); - - trace!("Starting"); - info!( - "crate ver {}, git hash {}", - env!("CARGO_PKG_VERSION"), - env!("GIT_HASH") - ); - trace!("Starting with Identity: {:?}", SETTING.get_identity()); - sanity_check_config(); - send_admin_notification_sms("Exit restarted"); - - let system = actix::System::new(format!("main {:?}", SETTING.get_network().mesh_ip)); - - check_rita_common_actors(); - check_rita_exit_actors(); - start_rita_exit_loop(); - let workers = SETTING.get_workers(); - start_core_rita_endpoints(workers as usize); - start_rita_exit_endpoints(workers as usize); - start_rita_exit_dashboard(); - - system.run(); -} - -fn start_rita_exit_dashboard() { - // Dashboard - server::new(|| { - App::new() - .middleware(middleware::Headers) - .route("/info", Method::GET, get_own_info) - .route("/local_fee", Method::GET, get_local_fee) - .route("/local_fee/{fee}", Method::POST, set_local_fee) - .route("/metric_factor", Method::GET, get_metric_factor) - .route("/metric_factor/{factor}", Method::POST, set_metric_factor) - .route("/settings", Method::GET, get_settings) - .route("/settings", Method::POST, set_settings) - .route("/version", Method::GET, version) - .route("/wg_public_key", Method::GET, get_wg_public_key) - .route("/wipe", Method::POST, wipe) - .route("/database", Method::DELETE, nuke_db) - .route("/debts", Method::GET, get_debts) - .route("/debts/reset", Method::POST, reset_debt) - .route("/withdraw/{address}/{amount}", Method::POST, withdraw) - .route("/withdraw_all/{address}", Method::POST, withdraw_all) - .route("/nickname/get/", Method::GET, get_nickname) - .route("/nickname/set/", Method::POST, set_nickname) - .route("/crash_actors", Method::POST, crash_actors) - .route("/usage/payments", Method::GET, get_payments) - .route("/token_bridge/status", Method::GET, get_bridge_status) - }) - .bind(format!( - "[::0]:{}", - SETTING.get_network().rita_dashboard_port - )) - .unwrap() - .workers(1) - .shutdown_timeout(0) - .start(); -} diff --git a/rita/src/rita_client/dashboard/auth.rs b/rita/src/rita_client/dashboard/auth.rs deleted file mode 100644 index c9886115e..000000000 --- a/rita/src/rita_client/dashboard/auth.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::ARGS; -use crate::KI; -use crate::SETTING; -use actix_web::{HttpResponse, Json}; -use clarity::utils::bytes_to_hex_str; -use failure::Error; -use settings::FileWrite; -use settings::RitaCommonSettings; -use sha3::{Digest, Sha3_512}; - -#[derive(Serialize, Deserialize, Default, Clone, Debug)] -pub struct RouterPassword { - pub password: String, -} - -pub fn set_pass(router_pass: Json) -> Result { - debug!("/router/password hit with {:?}", router_pass); - let router_pass = router_pass.into_inner(); - let input_string = router_pass.password.clone() + "RitaSalt"; - - debug!("Using {} as sha3 512 input", input_string); - let mut hasher = Sha3_512::new(); - hasher.update(input_string.as_bytes()); - let hashed_pass = bytes_to_hex_str(&hasher.finalize().to_vec()); - - SETTING.get_network_mut().rita_dashboard_password = Some(hashed_pass); - // try and save the config and fail if we can't - if let Err(e) = SETTING.write().unwrap().write(&ARGS.flag_config) { - trace!("Saved new password in config!"); - return Err(e); - } - - if KI.is_openwrt() { - KI.set_system_password(router_pass.password)?; - - // We edited disk contents, force global sync - KI.fs_sync()?; - } - - Ok(HttpResponse::Ok().json(())) -} - -#[test] -fn test_hash() { - let sha3_output = hex!("881c7d6ba98678bcd96e253086c4048c3ea15306d0d13ff48341c6285ee71102a47b6f16e20e4d65c0c3d677be689dfda6d326695609cbadfafa1800e9eb7fc1"); - - let mut hasher = Sha3_512::new(); - hasher.update(b"testing"); - let result = hasher.finalize().to_vec(); - - assert_eq!(result.len(), sha3_output.len()); - assert_eq!(result, sha3_output.to_vec()); -} - -#[test] -fn test_hash_to_string() { - let sha3sum_output = "881c7d6ba98678bcd96e253086c4048c3ea15306d0d13ff48341c6285ee71102a47b6f16e20e4d65c0c3d677be689dfda6d326695609cbadfafa1800e9eb7fc1"; - - let mut hasher = Sha3_512::new(); - hasher.update(b"testing"); - let result = hasher.finalize().to_vec(); - - assert_eq!(bytes_to_hex_str(&result), sha3sum_output); -} diff --git a/rita/src/rita_common/mod.rs b/rita/src/rita_common/mod.rs deleted file mode 100644 index cf6c26f80..000000000 --- a/rita/src/rita_common/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub mod blockchain_oracle; -pub mod dashboard; -pub mod debt_keeper; -pub mod hello_handler; -pub mod network_endpoints; -pub mod network_monitor; -pub mod payment_controller; -pub mod payment_validator; -pub mod peer_listener; -pub mod rita_loop; -pub mod simulated_txfee_manager; -pub mod token_bridge; -pub mod traffic_watcher; -pub mod tunnel_manager; -pub mod usage_tracker; -pub mod utils; diff --git a/rita/src/rita_exit/database/geoip.rs b/rita/src/rita_exit/database/geoip.rs deleted file mode 100644 index 7452cc368..000000000 --- a/rita/src/rita_exit/database/geoip.rs +++ /dev/null @@ -1,223 +0,0 @@ -use crate::rita_common::utils::ip_increment::is_unicast_link_local; -use crate::rita_exit::rita_loop::EXIT_LOOP_TIMEOUT; -use crate::KI; -use crate::SETTING; -use babel_monitor::open_babel_stream; -use babel_monitor::parse_routes; -use failure::Error; -use ipnetwork::IpNetwork; -use settings::exit::RitaExitSettings; -use settings::RitaCommonSettings; -use std::collections::HashMap; -use std::net::IpAddr; -use std::sync::{Arc, RwLock}; -use std::time::Duration; - -lazy_static! { - static ref GEOIP_CACHE: Arc>> = - Arc::new(RwLock::new(HashMap::new())); -} - -/// gets the gateway ip for a given mesh IP -pub fn get_gateway_ip_single(mesh_ip: IpAddr) -> Result { - let babel_port = SETTING.get_network().babel_port; - - let mut stream = open_babel_stream(babel_port, EXIT_LOOP_TIMEOUT)?; - - let routes = parse_routes(&mut stream)?; - - let mut route_to_des = None; - for route in routes.iter() { - // Only ip6 - if let IpNetwork::V6(ref ip) = route.prefix { - // Only host addresses and installed routes - if ip.prefix() == 128 && route.installed && IpAddr::V6(ip.ip()) == mesh_ip { - route_to_des = Some(route.clone()); - } - } - } - - match route_to_des { - Some(route) => Ok(KI.get_wg_remote_ip(&route.iface)?), - None => bail!("No route found for mesh ip: {:?}", mesh_ip), - } -} - -#[derive(Debug, Clone, Copy)] -pub struct IpPair { - pub mesh_ip: IpAddr, - pub gateway_ip: IpAddr, -} - -/// gets the gateway ip for a given set of mesh IPs, inactive addresses will simply -/// not appear in the result vec -pub fn get_gateway_ip_bulk(mesh_ip_list: Vec) -> Result, Error> { - let babel_port = SETTING.get_network().babel_port; - trace!("getting gateway ip bulk"); - - let mut stream = open_babel_stream(babel_port, EXIT_LOOP_TIMEOUT)?; - - let routes = parse_routes(&mut stream)?; - - trace!("done talking to babel for gateway ip bulk"); - let mut remote_ip_cache: HashMap = HashMap::new(); - let mut results = Vec::new(); - for mesh_ip in mesh_ip_list { - for route in routes.iter() { - // Only ip6 - if let IpNetwork::V6(ref ip) = route.prefix { - // Only host addresses and installed routes - if ip.prefix() == 128 && route.installed && IpAddr::V6(ip.ip()) == mesh_ip { - // check if we've already looked up this interface this round, since gateways - // have many clients this will often be the case - if let Some(remote_ip) = remote_ip_cache.get(&route.iface) { - results.push(IpPair { - mesh_ip, - gateway_ip: *remote_ip, - }); - } else { - match KI.get_wg_remote_ip(&route.iface) { - Ok(remote_ip) => { - remote_ip_cache.insert(route.iface.clone(), remote_ip); - results.push(IpPair { - mesh_ip, - gateway_ip: remote_ip, - }) - } - Err(e) => { - error!("Failure looking up remote ip {:?}", e) - } - } - } - } - } - } - } - Ok(results) -} - -#[derive(Deserialize, Debug)] -struct GeoIpRet { - country: CountryDetails, -} - -#[derive(Deserialize, Debug)] -struct CountryDetails { - iso_code: String, -} - -/// get ISO country code from ip, consults a in memory cache -pub fn get_country(ip: IpAddr) -> Result { - trace!("get GeoIP country for {}", ip.to_string()); - - // if allowed countries is not configured we don't care and will insert - // empty stings into the DB. - if SETTING.get_allowed_countries().is_empty() { - return Ok(String::new()); - } - - // in this case we have a gateway directly attached to the exit, so our - // peer address for them will be an fe80 linklocal ip address. When we - // detect this we go ahead and assign the user one of our allowed countries - // and move on. In the common case where we have only one allowed country - // this will produce the correct result. We can affirm this will never panic - // because we just checked that allowed countries contains at least one value - // above - if let IpAddr::V6(val) = ip { - if is_unicast_link_local(&val) { - return Ok(SETTING - .get_allowed_countries() - .iter() - .next() - .unwrap() - .clone()); - } - } - - // on the other hand if there is a configured list of allowed countries - // but no configured api details, we panic - let api_user = SETTING - .get_exit_network() - .geoip_api_user - .clone() - .expect("No api key configured!"); - let api_key = SETTING - .get_exit_network() - .geoip_api_key - .clone() - .expect("No api key configured!"); - - // we have to turn this option into a string in order to avoid - // the borrow checker trying to keep this lock open for a long period - let cache_result = GEOIP_CACHE - .read() - .unwrap() - .get(&ip) - .map(|val| val.to_string()); - - match cache_result { - Some(code) => Ok(code), - None => { - let geo_ip_url = format!("https://geoip.maxmind.com/geoip/v2.1/country/{}", ip); - info!( - "making GeoIP request to {} for {}", - geo_ip_url, - ip.to_string() - ); - let client = reqwest::blocking::Client::new(); - if let Ok(res) = client - .get(&geo_ip_url) - .basic_auth(api_user, Some(api_key)) - .timeout(Duration::from_secs(1)) - .send() - { - trace!("Got geoip result {:?}", res); - if let Ok(res) = res.json() { - let value: GeoIpRet = res; - let code = value.country.iso_code; - trace!("Adding GeoIP value {:?} to cache", code); - GEOIP_CACHE.write().unwrap().insert(ip, code.clone()); - trace!("Added to cache, returning"); - Ok(code) - } else { - Err(format_err!("Failed to deserialize geoip response")) - } - } else { - Err(format_err!("request failed")) - } - } - } -} - -/// Returns true or false if an ip is confirmed to be inside or outside the region and error -/// if an api error is encountered trying to figure that out. -pub fn verify_ip(request_ip: IpAddr) -> Result { - // in this case we have a gateway directly attached to the exit, so our - // peer address for them will be an fe80 linklocal ip address. When we - // detect this we know that they are in the allowed countries list because - // we assume the exit itself is in one of it's allowed countries. - if let IpAddr::V6(val) = request_ip { - if is_unicast_link_local(&val) { - return Ok(true); - } - } - - if SETTING.get_allowed_countries().is_empty() { - Ok(true) - } else { - let country = get_country(request_ip)?; - if !SETTING.get_allowed_countries().is_empty() - && !SETTING.get_allowed_countries().contains(&country) - { - return Ok(false); - } - - Ok(true) - } -} - -#[test] -#[ignore] -fn test_get_country() { - get_country("8.8.8.8".parse().unwrap()).unwrap(); -} diff --git a/rita/Cargo.toml b/rita_bin/Cargo.toml similarity index 63% rename from rita/Cargo.toml rename to rita_bin/Cargo.toml index 8d2dabb57..ae575c162 100644 --- a/rita/Cargo.toml +++ b/rita_bin/Cargo.toml @@ -1,9 +1,9 @@ [package] -name = "rita" +name = "rita_bin" version = "0.18.0" -authors = ["Justin ", "Jehan ", "Ben "] -build = "build.rs" edition = "2018" +license = "Apache-2.0" +build = "build.rs" [[bin]] name = "rita_exit" @@ -13,66 +13,55 @@ path = "src/exit.rs" name = "rita" path = "src/client.rs" +[[bin]] +name = "rita_tower" +path = "src/tower.rs" + [dependencies] althea_kernel_interface = { path = "../althea_kernel_interface" } +antenna_forwarding_client = {path = "../antenna_forwarding_client"} althea_types = { path = "../althea_types", features = ["actix"]} -babel_monitor = { path = "../babel_monitor" } -babel_monitor_legacy = {path = "../babel_monitor_legacy"} clu = { path = "../clu" } -exit_db = { path = "../exit_db" } -num256 = "0.3" -settings = { path = "../settings" } -antenna_forwarding_client = {path = "../antenna_forwarding_client"} -auto-bridge = {path = "../auto_bridge"} + + actix-web-httpauth = {git = "https://github.com/althea-net/actix-web-httpauth"} -clarity = "0.4" -web30 = {git = "https://github.com/althea-net/web30", rev = "a600b8b8ebf2c49badee6b65ac90a56bbdad4ab9"} -# duplicate async dependencies, we are currently carrying both futures 0.1 and modern async/await dependencies -# these will be kept here for quite some time until the switch is completed. -async-web30 = {package="web30", version = "0.14.6"} actix-async = {package="actix", version = "0.11"} -actix-web-async = {package="actix-web", version = "4.0.0-beta.8", default_features = false, features= ["openssl"] } +actix-web-async = {package="actix-web", version = "4.0.0-beta.6", default_features = false, features= ["openssl"] } actix = "0.7" actix-web = { version = "0.7", default_features = false, features= ["ssl"] } actix_derive = "0.5" -bytes = "1.0" -config = "0.11" -diesel = { version = "1.4", features = ["postgres", "r2d2"] } + docopt = "1.1" -dotenv = "0.15" -env_logger = "0.8" -failure = "0.1" -futures01 = { package = "futures", version = "0.1"} -futures = { version = "0.3", features = ["compat"] } -handlebars = "4.0" -ipnetwork = "0.14" -lazy_static = "1.4" + +compressed_log = "0.3.4" + +settings = { path = "../settings" } + +diesel = { version = "1.4", features = ["postgres", "r2d2"] } + log = { version = "0.4", features = ["release_max_level_info"] } -minihttpse = "0.1" -mockito = "0.30" -mockstream = "0.0" -rand = "0.8" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" -tokio = "0.1" -tokio-io = "0.1" -tokio-codec = "0.1" -trust-dns-resolver = "0.10" -byteorder = { version = "1.4", features = ["i128"] } -openssl-probe = "0.1" -num-traits="0.2" arrayvec = {version= "0.7", features = ["serde"]} -lettre = "0.9" -lettre_email = "0.9" +hex-literal = "0.3" +openssl-probe = "0.1" +env_logger = "0.8" + +lazy_static = "1.4" +failure = "0.1" + phonenumber = "0.3" r2d2 = "0.8" -sha3 = "0.9" -hex-literal = "0.3" -sodiumoxide = "0.2" -compressed_log = "0.3" + + +rita_common = { path = "../rita_common"} +rita_client = { path = "../rita_client"} +rita_exit = { path = "../rita_exit"} +rita_tower = { path = "../rita_tower"} + flate2 = { version = "1.0", features = ["rust_backend"], default-features = false } reqwest = { version = "0.11", features = ["blocking", "json"] } jemallocator = {version = "0.3", optional = true} diff --git a/rita/build.rs b/rita_bin/build.rs similarity index 100% rename from rita/build.rs rename to rita_bin/build.rs diff --git a/rita/src/client.rs b/rita_bin/src/client.rs similarity index 74% rename from rita/src/client.rs rename to rita_bin/src/client.rs index 8b310678c..4d3e561d6 100644 --- a/rita/src/client.rs +++ b/rita_bin/src/client.rs @@ -26,75 +26,62 @@ extern crate lazy_static; extern crate log; #[macro_use] extern crate serde_derive; -#[cfg(test)] -#[macro_use] -extern crate serde_json; -#[cfg(test)] -#[macro_use] -extern crate hex_literal; extern crate arrayvec; use actix_web::http::Method; use actix_web::{http, server, App}; use docopt::Docopt; +use rita_client::logging::enable_remote_logging; use rita_client::rita_loop::metrics_permitted; -use settings::client::{RitaClientSettings, RitaSettingsStruct}; -use settings::RitaCommonSettings; +use settings::client::RitaClientSettings; use std::env; -use std::sync::{Arc, RwLock}; use std::time::{Duration, Instant}; -#[cfg(not(test))] use settings::FileWrite; -#[cfg(test)] -use std::sync::Mutex; +use rita_client::rita_loop::check_rita_client_actors; +use rita_client::rita_loop::start_rita_client_endpoints; +use rita_common::dashboard::own_info::READABLE_VERSION; +use rita_common::rita_loop::check_rita_common_actors; +use rita_common::rita_loop::start_core_rita_endpoints; +use rita_common::utils::env_vars_contains; +use althea_kernel_interface::KernelInterface; +use althea_kernel_interface::LinuxCommandRunner; +use rita_client::dashboard::auth::*; +use rita_client::dashboard::backup_created::*; +use rita_client::dashboard::bandwidth_limit::*; +use rita_client::dashboard::contact_info::*; +use rita_client::dashboard::eth_private_key::*; +use rita_client::dashboard::exits::*; +use rita_client::dashboard::installation_details::*; +use rita_client::dashboard::interfaces::*; +use rita_client::dashboard::localization::*; +use rita_client::dashboard::logging::*; +use rita_client::dashboard::mesh_ip::*; +use rita_client::dashboard::neighbors::*; +use rita_client::dashboard::notifications::*; +use rita_client::dashboard::operator::*; +use rita_client::dashboard::prices::*; +use rita_client::dashboard::release_feed::*; +use rita_client::dashboard::remote_access::*; +use rita_client::dashboard::router::*; +use rita_client::dashboard::system_chain::*; +use rita_client::dashboard::usage::*; +use rita_client::dashboard::wifi::*; +use rita_client::heartbeat::HEARTBEAT_SERVER_KEY; +use rita_common::dashboard::babel::*; +use rita_common::dashboard::debts::*; +use rita_common::dashboard::development::*; +use rita_common::dashboard::nickname::*; +use rita_common::dashboard::own_info::*; +use rita_common::dashboard::settings::*; +use rita_common::dashboard::token_bridge::*; +use rita_common::dashboard::usage::*; +use rita_common::dashboard::wallet::*; +use rita_common::dashboard::wg_key::*; +use rita_common::network_endpoints::*; mod middleware; -mod rita_client; -mod rita_common; - -use crate::rita_client::enable_remote_logging; -use crate::rita_client::rita_loop::check_rita_client_actors; -use crate::rita_client::rita_loop::start_rita_client_endpoints; -use crate::rita_common::dashboard::own_info::READABLE_VERSION; -use crate::rita_common::rita_loop::check_rita_common_actors; -use crate::rita_common::rita_loop::start_core_rita_endpoints; -use crate::rita_common::utils::env_vars_contains; - -use crate::rita_client::dashboard::auth::*; -use crate::rita_client::dashboard::backup_created::*; -use crate::rita_client::dashboard::bandwidth_limit::*; -use crate::rita_client::dashboard::contact_info::*; -use crate::rita_client::dashboard::eth_private_key::*; -use crate::rita_client::dashboard::exits::*; -use crate::rita_client::dashboard::installation_details::*; -use crate::rita_client::dashboard::interfaces::*; -use crate::rita_client::dashboard::localization::*; -use crate::rita_client::dashboard::logging::*; -use crate::rita_client::dashboard::mesh_ip::*; -use crate::rita_client::dashboard::neighbors::*; -use crate::rita_client::dashboard::notifications::*; -use crate::rita_client::dashboard::operator::*; -use crate::rita_client::dashboard::prices::*; -use crate::rita_client::dashboard::release_feed::*; -use crate::rita_client::dashboard::remote_access::*; -use crate::rita_client::dashboard::router::*; -use crate::rita_client::dashboard::system_chain::*; -use crate::rita_client::dashboard::usage::*; -use crate::rita_client::dashboard::wifi::*; -use crate::rita_client::heartbeat::HEARTBEAT_SERVER_KEY; -use crate::rita_common::dashboard::babel::*; -use crate::rita_common::dashboard::debts::*; -use crate::rita_common::dashboard::development::*; -use crate::rita_common::dashboard::nickname::*; -use crate::rita_common::dashboard::own_info::*; -use crate::rita_common::dashboard::settings::*; -use crate::rita_common::dashboard::token_bridge::*; -use crate::rita_common::dashboard::usage::*; -use crate::rita_common::dashboard::wallet::*; -use crate::rita_common::dashboard::wg_key::*; -use crate::rita_common::network_endpoints::*; #[derive(Debug, Deserialize, Default)] pub struct Args { @@ -123,74 +110,22 @@ About: ); } -use althea_kernel_interface::KernelInterface; - -#[cfg(not(test))] -use althea_kernel_interface::LinuxCommandRunner; -#[cfg(test)] -use althea_kernel_interface::TestCommandRunner; - -#[cfg(test)] -lazy_static! { - pub static ref KI: Box = Box::new(TestCommandRunner { - run_command: Arc::new(Mutex::new(Box::new(|_program, _args| { - panic!("kernel interface used before initialized"); - }))) - }); -} - -#[cfg(test)] -lazy_static! { - pub static ref ARGS: Args = Args::default(); -} - -#[cfg(not(test))] lazy_static! { pub static ref KI: Box = Box::new(LinuxCommandRunner {}); } -#[cfg(not(test))] -lazy_static! { - pub static ref ARGS: Args = Docopt::new((*USAGE).as_str()) - .and_then(|d| d.deserialize()) - .unwrap_or_else(|e| e.exit()); -} - -#[cfg(not(test))] -lazy_static! { - pub static ref SETTING: Arc> = { - let settings_file = &ARGS.flag_config; - let platform = &ARGS.flag_platform; - - let s = RitaSettingsStruct::new_watched(settings_file).unwrap(); - - s.set_future(ARGS.flag_future); - - clu::init(platform, s.clone()); - - s.read().unwrap().write(settings_file).unwrap(); - s - }; -} - -#[cfg(test)] -lazy_static! { - pub static ref SETTING: Arc> = - Arc::new(RwLock::new(RitaSettingsStruct::default())); -} - /// Some devices (n600/n750) will provide junk file reads during disk init /// post flashing, this adds in retry for the settings file read for up to /// two minutes -fn wait_for_settings(settings_file: &str) -> RitaSettingsStruct { +fn wait_for_settings(settings_file: &str) -> RitaClientSettings { let start = Instant::now(); let timeout = Duration::from_secs(120); - let mut res = RitaSettingsStruct::new(settings_file); + let mut res = RitaClientSettings::new(settings_file); while (Instant::now() - start) < timeout { if let Ok(val) = res { return val; } - res = RitaSettingsStruct::new(settings_file); + res = RitaClientSettings::new(settings_file); } match res { Ok(val) => val, @@ -199,13 +134,40 @@ fn wait_for_settings(settings_file: &str) -> RitaSettingsStruct { } fn main() { + let args: Args = Docopt::new((*USAGE).as_str()) + .and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + + let settings_file = args.flag_config; + wait_for_settings(&settings_file); + + // load the settings file, setup a thread to save it out every so often + // and populate the memory cache of settings used throughout the program + let settings: RitaClientSettings = { + let platform = &args.flag_platform; + + let mut s = RitaClientSettings::new_watched(&settings_file).unwrap(); + + settings::set_flag_config(settings_file.to_string()); + + settings::set_git_hash(env!("GIT_HASH").to_string()); + + s.set_future(args.flag_future); + + let s = clu::init(platform, s); + + s.write(&settings_file).unwrap(); + settings::set_rita_client(s.clone()); + println!("Look the client settings! {:?}", s); + s + }; + // On Linux static builds we need to probe ssl certs path to be able to // do TLS stuff. openssl_probe::init_ssl_cert_env_vars(); // we should remove log if there's an operator address or if logging is enabled - let should_remote_log = - SETTING.get_log().enabled || SETTING.get_operator().operator_address.is_some(); + let should_remote_log = settings.log.enabled || settings.operator.operator_address.is_some(); // if remote logging is disabled, or the NO_REMOTE_LOG env var is set we should use the // local logger and log to std-out. Note we don't care what is actually set in NO_REMOTE_LOG // just that it is set @@ -227,31 +189,21 @@ fn main() { error!("Failed to setup cron!"); } - let args: Args = Docopt::new((*USAGE).as_str()) - .and_then(|d| d.deserialize()) - .unwrap_or_else(|e| e.exit()); - - let settings_file = args.flag_config; - - // to get errors before lazy static and make sure the config is ready to - // be read - wait_for_settings(&settings_file); - info!( "crate ver {}, git hash {}", env!("CARGO_PKG_VERSION"), env!("GIT_HASH") ); - trace!("Starting with Identity: {:?}", SETTING.get_identity()); + trace!("Starting with Identity: {:?}", settings.get_identity()); - let system = actix::System::new(format!("main {:?}", SETTING.get_network().mesh_ip)); + let system = actix::System::new(format!("main {:?}", settings.network.mesh_ip)); check_rita_common_actors(); check_rita_client_actors(); start_core_rita_endpoints(4); start_rita_client_endpoints(1); start_client_dashboard(); - start_antenna_forwarder(); + start_antenna_forwarder(settings); system.run(); info!("Started Rita Client!"); @@ -260,15 +212,15 @@ fn main() { /// starts the antenna forwarder, this is a logically independent set of code /// that does not care about anything else Rita is doing, it only deals with the /// actual physical interfaces and attempting to find antennas to forward on them. -fn start_antenna_forwarder() { +fn start_antenna_forwarder(settings: RitaClientSettings) { if metrics_permitted() { #[cfg(not(feature = "operator_debug"))] let url = "operator.althea.net:33334"; #[cfg(feature = "operator_debug")] let url = "192.168.10.2:33334"; - let network = SETTING.get_network(); - let our_id = SETTING.get_identity().unwrap(); + let our_id = settings.get_identity().unwrap(); + let network = settings.network; let mut interfaces = network.peer_interfaces.clone(); interfaces.insert("br-pbs".to_string()); start_antenna_forwarding_proxy( @@ -444,7 +396,9 @@ fn start_client_dashboard() { .workers(1) .bind(format!( "[::0]:{}", - SETTING.get_network().rita_dashboard_port + settings::get_rita_client() + .get_network() + .rita_dashboard_port )) .unwrap() .shutdown_timeout(0) diff --git a/rita_bin/src/exit.rs b/rita_bin/src/exit.rs new file mode 100644 index 000000000..7a6a06e55 --- /dev/null +++ b/rita_bin/src/exit.rs @@ -0,0 +1,193 @@ +//! This is the main source file for the Rita exit binary, by 'exit' we mean 'a vpn server, not a +//! mesh router out in the field'. +//! +//! All meshing and billing functionality is contained in `rita_common` and is common to both rita and +//! `rita_exit`. The major difference is billing and connection code for the 'exit', the mandatory +//! vpn system integrated into the Althea network design, as well as API endpoints for a management +//! dashboard of router functions like wifi, which the exit is not expected to have. +//! +//! This file initializes the dashboard endpoints for the exit as well as the common and exit +//! specific actors. + +#![warn(clippy::all)] +#![allow(clippy::pedantic)] +#![forbid(unsafe_code)] + +#[cfg(feature = "jemalloc")] +use jemallocator::Jemalloc; +#[cfg(feature = "jemalloc")] +#[global_allocator] +static GLOBAL: Jemalloc = Jemalloc; + +#[macro_use] +extern crate failure; +#[macro_use] +extern crate lazy_static; +#[macro_use] +extern crate log; +#[macro_use] +extern crate serde_derive; +extern crate phonenumber; + +use actix_web::http::Method; +use actix_web::{http, server, App}; +use docopt::Docopt; + +use settings::exit::RitaExitSettingsStruct; + +use rita_common::dashboard::own_info::READABLE_VERSION; +use rita_common::rita_loop::check_rita_common_actors; +use rita_common::rita_loop::start_core_rita_endpoints; +use rita_common::utils::env_vars_contains; +use rita_exit::database::sms::send_admin_notification_sms; +use rita_exit::logging::enable_remote_logging; +use rita_exit::rita_loop::check_rita_exit_actors; +use rita_exit::rita_loop::start_rita_exit_endpoints; +use rita_exit::rita_loop::start_rita_exit_loop; + +use rita_common::dashboard::babel::*; +use rita_common::dashboard::debts::*; +use rita_common::dashboard::development::*; +use rita_common::dashboard::nickname::*; +use rita_common::dashboard::own_info::*; +use rita_common::dashboard::settings::*; +use rita_common::dashboard::token_bridge::*; +use rita_common::dashboard::usage::*; +use rita_common::dashboard::wallet::*; +use rita_common::dashboard::wg_key::*; +use rita_common::network_endpoints::*; +use rita_exit::network_endpoints::*; +pub mod middleware; + +#[derive(Debug, Deserialize, Default)] +pub struct Args { + flag_config: String, + flag_future: bool, +} + +lazy_static! { + static ref USAGE: String = format!( + "Usage: rita_exit --config= +Options: + -c, --config= Name of config file + --future Enable B side of A/B releases +About: + Version {} - {} + git hash {}", + READABLE_VERSION, + env!("CARGO_PKG_VERSION"), + env!("GIT_HASH") + ); +} + +/// used to crash the exit on first startup if config does not make sense +/// as is usually desirable for cloud infrastruture +fn sanity_check_config() { + let exit_settings = settings::get_rita_exit(); + if !exit_settings.allowed_countries.is_empty() + && exit_settings.exit_network.geoip_api_key.is_none() + { + panic!("GEOIP enforcement configured but not api key provided!"); + } +} + +fn main() { + let args: Args = Docopt::new((*USAGE).as_str()) + .and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + + // load the settings file, setup a thread to save it out every so often + // and populate the memory cache of settings used throughout the program + let settings = { + let settings_file = args.flag_config; + let settings = RitaExitSettingsStruct::new_watched(&settings_file).unwrap(); + + settings::set_git_hash(env!("GIT_HASH").to_string()); + + let settings = clu::exit_init("linux", settings); + settings::set_rita_exit(settings.clone()); + sanity_check_config(); + println!("Look the exit settings! {:?}", settings); + settings + }; + + // On Linux static builds we need to probe ssl certs path to be able to + // do TLS stuff. + openssl_probe::init_ssl_cert_env_vars(); + + // An exit setting dictating if this exit operator wants to log remotely or locally + let should_remote_log = settings.remote_log; + // if remote logging is disabled, or the NO_REMOTE_LOG env var is set we should use the + // local logger and log to std-out. Note we don't care what is actually set in NO_REMOTE_LOG + // just that it is set + if !should_remote_log || env_vars_contains("NO_REMOTE_LOG") { + env_logger::init(); + } else { + let res = enable_remote_logging(); + println!("logging status {:?}", res); + } + + if cfg!(feature = "development") { + println!("Warning!"); + println!("This build is meant only for development purposes."); + println!("Running this on production as an exit node is unsupported and not safe!"); + } + + trace!("Starting"); + info!( + "crate ver {}, git hash {}", + env!("CARGO_PKG_VERSION"), + env!("GIT_HASH") + ); + trace!("Starting with Identity: {:?}", settings.get_identity()); + + send_admin_notification_sms("Exit restarted"); + + let system = actix::System::new(format!("main {:?}", settings.network.mesh_ip)); + + check_rita_common_actors(); + check_rita_exit_actors(); + start_rita_exit_loop(); + let workers = settings.workers; + start_core_rita_endpoints(workers as usize); + start_rita_exit_endpoints(workers as usize); + start_rita_exit_dashboard(); + + system.run(); +} + +fn start_rita_exit_dashboard() { + // Dashboard + server::new(|| { + App::new() + .middleware(middleware::Headers) + .route("/info", Method::GET, get_own_info) + .route("/local_fee", Method::GET, get_local_fee) + .route("/local_fee/{fee}", Method::POST, set_local_fee) + .route("/metric_factor", Method::GET, get_metric_factor) + .route("/metric_factor/{factor}", Method::POST, set_metric_factor) + .route("/settings", Method::GET, get_settings) + .route("/settings", Method::POST, set_settings) + .route("/version", Method::GET, version) + .route("/wg_public_key", Method::GET, get_wg_public_key) + .route("/wipe", Method::POST, wipe) + .route("/database", Method::DELETE, nuke_db) + .route("/debts", Method::GET, get_debts) + .route("/debts/reset", Method::POST, reset_debt) + .route("/withdraw/{address}/{amount}", Method::POST, withdraw) + .route("/withdraw_all/{address}", Method::POST, withdraw_all) + .route("/nickname/get/", Method::GET, get_nickname) + .route("/nickname/set/", Method::POST, set_nickname) + .route("/crash_actors", Method::POST, crash_actors) + .route("/usage/payments", Method::GET, get_payments) + .route("/token_bridge/status", Method::GET, get_bridge_status) + }) + .bind(format!( + "[::0]:{}", + settings::get_rita_exit().network.rita_dashboard_port + )) + .unwrap() + .workers(1) + .shutdown_timeout(0) + .start(); +} diff --git a/rita/src/middleware.rs b/rita_bin/src/middleware.rs similarity index 95% rename from rita/src/middleware.rs rename to rita_bin/src/middleware.rs index ed82172a2..ce3e27b83 100644 --- a/rita/src/middleware.rs +++ b/rita_bin/src/middleware.rs @@ -2,13 +2,11 @@ //! the client dashboard use crate::http::{header, HttpTryFrom, Method, StatusCode}; -use crate::SETTING; use actix_web::middleware::{Middleware, Response, Started}; use actix_web::{FromRequest, HttpRequest, HttpResponse, Result}; use actix_web_httpauth::extractors::basic::{BasicAuth, Config}; use actix_web_httpauth::extractors::AuthenticationError; use regex::Regex; -use settings::RitaCommonSettings; pub struct Headers; @@ -65,7 +63,7 @@ pub struct Auth; impl Middleware for Auth { fn start(&self, req: &HttpRequest) -> Result { - let password = SETTING.get_network().rita_dashboard_password.clone(); + let password = settings::get_rita_client().network.rita_dashboard_password; let mut config = Config::default(); // the /exits path is exempted from authenticaiton so that the diff --git a/rita_bin/src/tower.rs b/rita_bin/src/tower.rs new file mode 100644 index 000000000..403237f54 --- /dev/null +++ b/rita_bin/src/tower.rs @@ -0,0 +1,192 @@ +use althea_types::WgKey; +pub(crate) use antenna_forwarding_client::start_antenna_forwarding_proxy; +use compressed_log::builder::LoggerBuilder; +use compressed_log::compression::Compression; +#[cfg(feature = "jemalloc")] +use jemallocator::Jemalloc; +#[cfg(feature = "jemalloc")] +#[global_allocator] +static GLOBAL: Jemalloc = Jemalloc; + +#[macro_use] +extern crate failure; +#[macro_use] +extern crate lazy_static; +#[macro_use] +extern crate log; +#[macro_use] +extern crate serde_derive; +#[cfg(test)] +extern crate arrayvec; + +use docopt::Docopt; +use log::{LevelFilter, Record}; +use settings::client::RitaClientSettings; + +use settings::FileWrite; +use std::env; + +use failure::Error; + +use rita_common::dashboard::own_info::READABLE_VERSION; +use rita_common::rita_loop::check_rita_common_actors; +use rita_common::rita_loop::start_core_rita_endpoints; +use rita_common::utils::env_vars_contains; + +#[derive(Debug, Deserialize, Default)] +pub struct Args { + flag_config: String, + flag_platform: String, + flag_future: bool, +} + +lazy_static! { + pub static ref HEARTBEAT_SERVER_KEY: WgKey = "hizclQFo/ArWY+/9+AJ0LBY2dTiQK4smy5icM7GA5ng=" + .parse() + .unwrap(); +} + +lazy_static! { + static ref USAGE: String = format!( + "Usage: rita --config= --platform= [--future] +Options: + -c, --config= Name of config file + --future Enable B side of A/B releases +About: + Version {} - {} + git hash {}", + READABLE_VERSION, + env!("CARGO_PKG_VERSION"), + env!("GIT_HASH") + ); +} + +use althea_kernel_interface::KernelInterface; +use althea_kernel_interface::LinuxCommandRunner; + +lazy_static! { + pub static ref KI: Box = Box::new(LinuxCommandRunner {}); +} + +lazy_static! { + pub static ref ARGS: Args = Docopt::new((*USAGE).as_str()) + .and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); +} + +lazy_static! { + pub static ref SETTING: RitaClientSettings = { + let settings_file = &ARGS.flag_config; + let platform = &ARGS.flag_platform; + + let mut s = RitaClientSettings::new_watched(settings_file).unwrap(); + + s.set_future(ARGS.flag_future); + + let s = clu::init(platform, s); + + s.write(settings_file).unwrap(); + s + }; +} + +fn main() { + // On Linux static builds we need to probe ssl certs path to be able to + // do TLS stuff. + openssl_probe::init_ssl_cert_env_vars(); + + let should_remote_log = SETTING.log.enabled || SETTING.operator.operator_address.is_some(); + // if remote logging is disabled, or the NO_REMOTE_LOG env var is set we should use the + // local logger and log to std-out. Note we don't care what is actually set in NO_REMOTE_LOG + // just that it is set + if !should_remote_log || env_vars_contains("NO_REMOTE_LOG") { + env_logger::init(); + } else { + let res = enable_remote_logging(); + println!("logging status {:?}", res); + } + + let _args: Args = Docopt::new((*USAGE).as_str()) + .and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + + info!( + "crate ver {}, git hash {}", + env!("CARGO_PKG_VERSION"), + env!("GIT_HASH") + ); + + check_rita_common_actors(); + start_core_rita_endpoints(4); + start_antenna_forwarder(); +} +/// starts the antenna forwarder, this is a logically independent set of code +/// that does not care about anything else Rita is doing, it only deals with the +/// actual physical interfaces and attempting to find antennas to forward on them. +fn start_antenna_forwarder() { + #[cfg(not(feature = "operator_debug"))] + let url = "operator.althea.net:33334"; + #[cfg(feature = "operator_debug")] + let url = "192.168.10.2:33334"; + + let network = SETTING.get_network(); + let our_id = SETTING.get_identity().unwrap(); + let mut interfaces = network.peer_interfaces.clone(); + interfaces.insert("br-pbs".to_string()); + start_antenna_forwarding_proxy( + url.to_string(), + our_id, + *HEARTBEAT_SERVER_KEY, + network.wg_public_key.unwrap(), + network.wg_private_key.unwrap(), + interfaces, + ); +} +/// enables remote logging if the user has configured it +pub fn enable_remote_logging() -> Result<(), Error> { + trace!("About to enable remote logging"); + let log = &SETTING.log; + let key = SETTING + .get_network() + .wg_public_key + .expect("Tried to init remote logging without WgKey!"); + let logging_url = &log.dest_url; + let level: LevelFilter = match log.level.parse() { + Ok(level) => level, + Err(_) => LevelFilter::Error, + }; + + let logger = LoggerBuilder::default() + .set_level( + level + .to_level() + .ok_or_else(|| format_err!("Unable to convert level filter to a level"))?, + ) + .set_compression_level(Compression::Fast) + .set_sink_url(logging_url) + .set_threshold(1000) + .set_format(Box::new(move |record: &Record| { + format!( + "{} {} rita: {}\n", + key, + env!("CARGO_PKG_VERSION"), + record.args() + ) + })) + .build(); + if let Err(e) = logger { + bail!(format_err!("{}", e)) + } + let logger = logger.unwrap(); + + if let Err(e) = log::set_boxed_logger(Box::new(logger)) { + bail!(format_err!("{}", e)) + } + log::set_max_level(level); + + println!( + "Remote compressed logging enabled with target {}", + logging_url + ); + Ok(()) +} diff --git a/rita_client/Cargo.toml b/rita_client/Cargo.toml new file mode 100644 index 000000000..c45f732cb --- /dev/null +++ b/rita_client/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "rita_client" +version = "0.18.0" +edition = "2018" +license = "Apache-2.0" + + +[dependencies] +compressed_log = "0.3.4" +num-traits="0.2" +num256 = "0.3" +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0" +lazy_static = "1.4" +hex-literal = "0.3" +failure = "0.1" +rita_common = { path = "../rita_common" } +futures01 = { package = "futures", version = "0.1"} +log = { version = "0.4", features = ["release_max_level_info"] } +althea_types = { path = "../althea_types" } +althea_kernel_interface = { path = "../althea_kernel_interface" } +settings = { path = "../settings" } +sha3 = "0.9" +lettre = "0.9" +lettre_email = "0.9" +phonenumber = "0.3" +babel_monitor = { path = "../babel_monitor" } +babel_monitor_legacy = {path = "../babel_monitor_legacy"} +arrayvec = {version= "0.7", features = ["serde"]} +tokio = "0.1" +tokio-io = "0.1" +tokio-codec = "0.1" +sodiumoxide = "0.2" +clu = { path = "../clu" } +web30 = {git = "https://github.com/althea-net/web30", rev = "a600b8b8ebf2c49badee6b65ac90a56bbdad4ab9"} + +actix = "0.7" +actix-web = { version = "0.7", default_features = false, features= ["ssl"] } + +clarity = "0.4" + +[lib] +name = "rita_client" +path = "src/lib.rs" \ No newline at end of file diff --git a/rita_client/src/dashboard/auth.rs b/rita_client/src/dashboard/auth.rs new file mode 100644 index 000000000..230e00074 --- /dev/null +++ b/rita_client/src/dashboard/auth.rs @@ -0,0 +1,74 @@ +use rita_common::KI; + +use actix_web::{HttpResponse, Json}; +use clarity::utils::bytes_to_hex_str; +use failure::Error; +use settings::FileWrite; +use sha3::{Digest, Sha3_512}; + +#[derive(Serialize, Deserialize, Default, Clone, Debug)] +pub struct RouterPassword { + pub password: String, +} + +pub fn set_pass(router_pass: Json) -> Result { + debug!("/router/password hit with {:?}", router_pass); + let router_pass = router_pass.into_inner(); + let input_string = router_pass.password.clone() + "RitaSalt"; + + debug!("Using {} as sha3 512 input", input_string); + let mut hasher = Sha3_512::new(); + hasher.update(input_string.as_bytes()); + let hashed_pass = bytes_to_hex_str(&hasher.finalize().to_vec()); + let mut network = settings::get_rita_client().network; + network.rita_dashboard_password = Some(hashed_pass); + // try and save the config and fail if we can't + let rita_client = settings::get_rita_client(); + if let Err(e) = rita_client.write(&settings::get_flag_config()) { + return Err(e); + } else { + settings::set_rita_client(rita_client); + } + + if KI.is_openwrt() { + KI.set_system_password(router_pass.password)?; + + // We edited disk contents, force global sync + KI.fs_sync()?; + } + let mut rita_client = settings::get_rita_client(); + rita_client.network = network; + settings::set_rita_client(rita_client); + + Ok(HttpResponse::Ok().json(())) +} + +#[cfg(test)] +mod tests { + use clarity::utils::bytes_to_hex_str; + use hex_literal::hex; + use sha3::{Digest, Sha3_512}; + + #[test] + fn test_hash() { + let sha3_output = hex!("881c7d6ba98678bcd96e253086c4048c3ea15306d0d13ff48341c6285ee71102a47b6f16e20e4d65c0c3d677be689dfda6d326695609cbadfafa1800e9eb7fc1"); + + let mut hasher = Sha3_512::new(); + hasher.update(b"testing"); + let result = hasher.finalize().to_vec(); + + assert_eq!(result.len(), sha3_output.len()); + assert_eq!(result, sha3_output.to_vec()); + } + + #[test] + fn test_hash_to_string() { + let sha3sum_output = "881c7d6ba98678bcd96e253086c4048c3ea15306d0d13ff48341c6285ee71102a47b6f16e20e4d65c0c3d677be689dfda6d326695609cbadfafa1800e9eb7fc1"; + + let mut hasher = Sha3_512::new(); + hasher.update(b"testing"); + let result = hasher.finalize().to_vec(); + + assert_eq!(bytes_to_hex_str(&result), sha3sum_output); + } +} diff --git a/rita/src/rita_client/dashboard/backup_created.rs b/rita_client/src/dashboard/backup_created.rs similarity index 55% rename from rita/src/rita_client/dashboard/backup_created.rs rename to rita_client/src/dashboard/backup_created.rs index 1eeded313..ad8219a83 100644 --- a/rita/src/rita_client/dashboard/backup_created.rs +++ b/rita_client/src/dashboard/backup_created.rs @@ -1,10 +1,7 @@ -use crate::ARGS; -use crate::SETTING; use actix_web::Path; use actix_web::{HttpRequest, HttpResponse, Result}; use failure::Error; use settings::FileWrite; -use settings::RitaCommonSettings; use std::collections::HashMap; pub fn get_backup_created(_req: HttpRequest) -> Result { @@ -12,7 +9,10 @@ pub fn get_backup_created(_req: HttpRequest) -> Result { let mut ret = HashMap::new(); ret.insert( "backup_created", - SETTING.get_network().backup_created.to_string(), + settings::get_rita_client() + .get_network() + .backup_created + .to_string(), ); Ok(HttpResponse::Ok().json(ret)) @@ -21,11 +21,19 @@ pub fn get_backup_created(_req: HttpRequest) -> Result { pub fn set_backup_created(path: Path) -> Result { debug!("Setting backup created"); let value = path.into_inner(); - SETTING.get_network_mut().backup_created = value; + + let mut network = settings::get_rita_client().network; + network.backup_created = value; // try and save the config and fail if we can't - if let Err(e) = SETTING.write().unwrap().write(&ARGS.flag_config) { + let rita_client = settings::get_rita_client(); + if let Err(e) = rita_client.write(&settings::get_flag_config()) { return Err(e); + } else { + settings::set_rita_client(rita_client); } + let mut rita_client = settings::get_rita_client(); + rita_client.network = network; + settings::set_rita_client(rita_client); Ok(HttpResponse::Ok().json(())) } diff --git a/rita/src/rita_client/dashboard/bandwidth_limit.rs b/rita_client/src/dashboard/bandwidth_limit.rs similarity index 52% rename from rita/src/rita_client/dashboard/bandwidth_limit.rs rename to rita_client/src/dashboard/bandwidth_limit.rs index 93bb9aa12..6ac5b9ff6 100644 --- a/rita/src/rita_client/dashboard/bandwidth_limit.rs +++ b/rita_client/src/dashboard/bandwidth_limit.rs @@ -1,38 +1,42 @@ //! Beta 16 introduces a feature where users can select their own self imposed router bandwidth limit //! these dashboard endpoints facilitate users setting that value. -use crate::ARGS; -use crate::KI; -use crate::SETTING; use actix_web::HttpResponse; use actix_web::{HttpRequest, Path}; use failure::Error; +use rita_common::KI; use settings::FileWrite; -use settings::RitaCommonSettings; pub fn get_bandwidth_limit(_req: HttpRequest) -> HttpResponse { - let val = SETTING.get_network().user_bandwidth_limit; + let val = settings::get_rita_client() + .get_network() + .user_bandwidth_limit; HttpResponse::Ok().json(val) } pub fn set_bandwidth_limit(path: Path) -> Result { let value = path.into_inner(); debug!("Set bandwidth limit!"); - let mut net = SETTING.get_network_mut(); + let mut rita_client = settings::get_rita_client(); + let mut network = rita_client.network; if value.is_empty() || value == "disable" { - net.user_bandwidth_limit = None; + network.user_bandwidth_limit = None; } else if let Ok(parsed) = value.parse() { - net.user_bandwidth_limit = Some(parsed); + network.user_bandwidth_limit = Some(parsed); } else { return Ok(HttpResponse::BadRequest().finish()); } - let _res = KI.set_codel_shaping("wg_exit", net.user_bandwidth_limit, true); - let _res = KI.set_codel_shaping("br-lan", net.user_bandwidth_limit, false); - drop(net); + let _res = KI.set_codel_shaping("wg_exit", network.user_bandwidth_limit, true); + let _res = KI.set_codel_shaping("br-lan", network.user_bandwidth_limit, false); + rita_client.network = network; + settings::set_rita_client(rita_client); // try and save the config and fail if we can't - if let Err(e) = SETTING.write().unwrap().write(&ARGS.flag_config) { + let rita_client = settings::get_rita_client(); + if let Err(e) = rita_client.write(&settings::get_flag_config()) { return Err(e); + } else { + settings::set_rita_client(rita_client); } Ok(HttpResponse::Ok().json(())) } diff --git a/rita/src/rita_client/dashboard/contact_info.rs b/rita_client/src/dashboard/contact_info.rs similarity index 76% rename from rita/src/rita_client/dashboard/contact_info.rs rename to rita_client/src/dashboard/contact_info.rs index 49598b0bd..3f3b4c832 100644 --- a/rita/src/rita_client/dashboard/contact_info.rs +++ b/rita_client/src/dashboard/contact_info.rs @@ -2,15 +2,14 @@ //! we end up processing and moving contact data in a few other places (exit registration, text notifications) the contact_details member of //! the exit settings struct is the one true source. All the others are updated as needed and you should try to phase them out if practical. -use crate::rita_common::utils::option_convert; -use crate::ARGS; -use crate::SETTING; +use rita_common::utils::option_convert; + use actix_web::HttpRequest; use actix_web::HttpResponse; use althea_types::ContactType; use lettre::EmailAddress; use phonenumber::PhoneNumber; -use settings::{client::RitaClientSettings, FileWrite}; +use settings::FileWrite; fn clean_quotes(val: &str) -> String { val.trim().trim_matches('"').trim_matches('\\').to_string() @@ -26,7 +25,8 @@ pub fn set_phone_number(req: String) -> HttpResponse { return HttpResponse::BadRequest().finish(); } }; - let mut exit_client = SETTING.get_exit_client_mut(); + + let mut exit_client = settings::get_rita_client().exit_client; // merge the new value into the existing struct, for the various possibilities let res = match option_convert(exit_client.contact_info.clone()) { Some(ContactType::Phone { .. }) => Some(ContactType::Phone { number }), @@ -38,20 +38,26 @@ pub fn set_phone_number(req: String) -> HttpResponse { Some(ContactType::Bad { .. }) => Some(ContactType::Phone { number }), None => Some(ContactType::Phone { number }), }; + let mut rita_client = settings::get_rita_client(); exit_client.contact_info = option_convert(res); - drop(exit_client); + rita_client.exit_client = exit_client; + settings::set_rita_client(rita_client); // try and save the config and fail if we can't - if let Err(_e) = SETTING.write().unwrap().write(&ARGS.flag_config) { + let rita_client = settings::get_rita_client(); + if let Err(_e) = rita_client.write(&settings::get_flag_config()) { return HttpResponse::InternalServerError().finish(); + } else { + settings::set_rita_client(rita_client); } HttpResponse::Ok().finish() } pub fn get_phone_number(_req: HttpRequest) -> HttpResponse { - let exit_client = SETTING.get_exit_client(); - match &option_convert(exit_client.contact_info.clone()) { + let rita_client = settings::get_rita_client(); + let exit_client = rita_client.exit_client; + match &option_convert(exit_client.contact_info) { Some(ContactType::Phone { number }) => HttpResponse::Ok().json(number.to_string()), Some(ContactType::Both { email: _email, @@ -71,7 +77,8 @@ pub fn set_email(req: String) -> HttpResponse { return HttpResponse::BadRequest().finish(); } }; - let mut exit_client = SETTING.get_exit_client_mut(); + + let mut exit_client = settings::get_rita_client().exit_client; // merge the new value into the existing struct, for the various possibilities let res = match option_convert(exit_client.contact_info.clone()) { Some(ContactType::Phone { number }) => Some(ContactType::Both { number, email }), @@ -84,19 +91,25 @@ pub fn set_email(req: String) -> HttpResponse { None => Some(ContactType::Email { email }), }; exit_client.contact_info = option_convert(res); - drop(exit_client); // try and save the config and fail if we can't - if let Err(_e) = SETTING.write().unwrap().write(&ARGS.flag_config) { + let rita_client = settings::get_rita_client(); + if let Err(_e) = rita_client.write(&settings::get_flag_config()) { return HttpResponse::InternalServerError().finish(); + } else { + settings::set_rita_client(rita_client); } + let mut rita_client = settings::get_rita_client(); + rita_client.exit_client = exit_client; + settings::set_rita_client(rita_client); HttpResponse::Ok().finish() } pub fn get_email(_req: HttpRequest) -> HttpResponse { - let exit_client = SETTING.get_exit_client(); - match &option_convert(exit_client.contact_info.clone()) { + let rita_client = settings::get_rita_client(); + let exit_client = rita_client.exit_client; + match &option_convert(exit_client.contact_info) { Some(ContactType::Email { email }) => HttpResponse::Ok().json(email.to_string()), Some(ContactType::Both { number: _number, diff --git a/rita/src/rita_client/dashboard/eth_private_key.rs b/rita_client/src/dashboard/eth_private_key.rs similarity index 87% rename from rita/src/rita_client/dashboard/eth_private_key.rs rename to rita_client/src/dashboard/eth_private_key.rs index f082bea5f..3419d7a04 100644 --- a/rita/src/rita_client/dashboard/eth_private_key.rs +++ b/rita_client/src/dashboard/eth_private_key.rs @@ -1,7 +1,5 @@ -use crate::SETTING; use actix_web::{HttpRequest, HttpResponse}; use failure::Error; -use settings::RitaCommonSettings; use std::collections::HashMap; #[derive(Serialize, Deserialize, Default, Clone, Debug)] @@ -14,7 +12,7 @@ pub fn get_eth_private_key(_req: HttpRequest) -> Result { let mut ret = HashMap::new(); - match SETTING.get_payment().eth_private_key { + match settings::get_rita_client().get_payment().eth_private_key { Some(pk) => { ret.insert("eth_private_key".to_owned(), format!("{:x}", pk)); } diff --git a/rita/src/rita_client/dashboard/exits.rs b/rita_client/src/dashboard/exits.rs similarity index 87% rename from rita/src/rita_client/dashboard/exits.rs rename to rita_client/src/dashboard/exits.rs index 89b065335..50910a15f 100644 --- a/rita/src/rita_client/dashboard/exits.rs +++ b/rita_client/src/dashboard/exits.rs @@ -1,10 +1,6 @@ //! The Exit info endpoint gathers infromation about exit status and presents it to the dashbaord. -use crate::rita_client::exit_manager::exit_setup_request; -use crate::rita_common::dashboard::Dashboard; -use crate::ARGS; -use crate::KI; -use crate::SETTING; +use crate::exit_manager::exit_setup_request; use actix::{Handler, Message, ResponseFuture, SystemService}; use actix_web::http::StatusCode; use actix_web::AsyncResponder; @@ -17,9 +13,10 @@ use babel_monitor_legacy::parse_routes_legacy; use babel_monitor_legacy::start_connection_legacy; use failure::Error; use futures01::{future, Future}; -use settings::client::{ExitServer, RitaClientSettings}; +use rita_common::dashboard::Dashboard; +use rita_common::KI; +use settings::client::ExitServer; use settings::FileWrite; -use settings::RitaCommonSettings; use std::boxed::Box; use std::collections::HashMap; use std::time::Duration; @@ -68,7 +65,7 @@ impl Handler for Dashboard { type Result = ResponseFuture, Error>; fn handle(&mut self, _msg: GetExitInfo, _ctx: &mut Self::Context) -> Self::Result { - let babel_port = SETTING.get_network().babel_port; + let babel_port = settings::get_rita_client().get_network().babel_port; Box::new( open_babel_stream_legacy(babel_port) @@ -78,8 +75,8 @@ impl Handler for Dashboard { parse_routes_legacy(stream).and_then(move |routes| { let route_table_sample = routes.1; let mut output = Vec::new(); - - let exit_client = SETTING.get_exit_client(); + let rita_client = settings::get_rita_client(); + let exit_client = rita_client.exit_client; let current_exit = exit_client.get_current_exit(); for exit in exit_client.exits.clone().into_iter() { @@ -121,10 +118,16 @@ pub fn add_exits( new_exits: Json>, ) -> Box> { debug!("/exits POST hit with {:?}", new_exits); - let exits = &mut SETTING.get_exit_client_mut().exits; + let mut rita_client = settings::get_rita_client(); + let mut exits = rita_client.exit_client.exits; exits.extend(new_exits.into_inner()); - Box::new(future::ok(HttpResponse::Ok().json(exits.clone()))) + let copy = exits.clone(); + + rita_client.exit_client.exits = exits; + settings::set_rita_client(rita_client); + + Box::new(future::ok(HttpResponse::Ok().json(copy))) } pub fn get_exit_info( @@ -141,8 +144,9 @@ pub fn get_exit_info( pub fn reset_exit(path: Path) -> Box> { let exit_name = path.into_inner(); debug!("/exits/{}/reset hit", exit_name); + let mut rita_client = settings::get_rita_client(); - let mut exits = SETTING.get_exits_mut(); + let mut exits = rita_client.exit_client.exits; let mut ret = HashMap::new(); if let Some(exit) = exits.get_mut(&exit_name) { @@ -155,7 +159,8 @@ pub fn reset_exit(path: Path) -> Box) -> Box) -> Box) -> HttpRespo let input = req.into_inner(); trace!("Setting install details with {:?}", input); - let mut exit_client = SETTING.get_exit_client_mut(); + let mut rita_client = settings::get_rita_client(); + let mut exit_client = rita_client.exit_client; let contact_details = match (input.phone, input.email) { (None, None) => return HttpResponse::BadRequest().finish(), (Some(phone), Some(email)) => match (phone.parse(), email.parse()) { @@ -90,7 +89,8 @@ pub fn set_installation_details(req: Json) -> HttpRespo // stored separately since it's used elsewhere and sent to the operator tools // on it's own. exit_client.contact_info = Some(contact_details.into()); - drop(exit_client); + rita_client.exit_client = exit_client; + settings::set_rita_client(rita_client); let new_installation_details = InstallationDetails { client_antenna_ip: parsed_client_antenna_ip, @@ -112,50 +112,67 @@ pub fn set_installation_details(req: Json) -> HttpRespo }, }; - let mut operator_settings = SETTING.get_operator_mut(); - operator_settings.installation_details = Some(new_installation_details); - operator_settings.billing_details = Some(new_billing_details); - operator_settings.display_operator_setup = false; + let mut rita_client = settings::get_rita_client(); + let mut operator = rita_client.operator; + operator.installation_details = Some(new_installation_details); + operator.billing_details = Some(new_billing_details); + operator.display_operator_setup = false; - drop(operator_settings); + rita_client.operator = operator; + settings::set_rita_client(rita_client); // try and save the config and fail if we can't - if let Err(_e) = SETTING.write().unwrap().write(&ARGS.flag_config) { + let rita_client = settings::get_rita_client(); + if let Err(_e) = rita_client.write(&settings::get_flag_config()) { return HttpResponse::InternalServerError().finish(); + } else { + settings::set_rita_client(rita_client); } HttpResponse::Ok().finish() } pub fn get_installation_details(_req: HttpRequest) -> HttpResponse { - let operator_settings = SETTING.get_operator(); - HttpResponse::Ok().json(operator_settings.installation_details.clone()) + let rita_client = settings::get_rita_client(); + let operator_settings = rita_client.operator; + HttpResponse::Ok().json(operator_settings.installation_details) } pub fn display_operator_setup(_req: HttpRequest) -> HttpResponse { - HttpResponse::Ok().json(SETTING.get_operator().display_operator_setup) + HttpResponse::Ok().json(settings::get_rita_client().operator.display_operator_setup) } pub fn set_display_operator_setup(val: Path) -> HttpResponse { // scoped so that this value gets dropped before we get to save, preventing // deadlock { - SETTING.get_operator_mut().display_operator_setup = val.into_inner(); + let mut rita_client = settings::get_rita_client(); + let mut operator = rita_client.operator; + operator.display_operator_setup = val.into_inner(); + rita_client.operator = operator; + settings::set_rita_client(rita_client); } // try and save the config and fail if we can't - if let Err(_e) = SETTING.write().unwrap().write(&ARGS.flag_config) { + let rita_client = settings::get_rita_client(); + if let Err(_e) = rita_client.write(&settings::get_flag_config()) { return HttpResponse::InternalServerError().finish(); + } else { + settings::set_rita_client(rita_client); } HttpResponse::Ok().finish() } pub fn get_billing_details(_req: HttpRequest) -> HttpResponse { - let operator_settings = SETTING.get_operator(); - HttpResponse::Ok().json(operator_settings.billing_details.clone()) + let rita_client = settings::get_rita_client(); + let operator_settings = rita_client.operator; + HttpResponse::Ok().json(operator_settings.billing_details) } pub fn set_billing_details(req: Json) -> HttpResponse { - let mut operator_settings = SETTING.get_operator_mut(); - operator_settings.billing_details = Some(req.into_inner()); + let mut rita_client = settings::get_rita_client(); + let mut operator = rita_client.operator; + operator.billing_details = Some(req.into_inner()); + rita_client.operator = operator; + settings::set_rita_client(rita_client); HttpResponse::Ok().finish() } diff --git a/rita/src/rita_client/dashboard/interfaces.rs b/rita_client/src/dashboard/interfaces.rs similarity index 95% rename from rita/src/rita_client/dashboard/interfaces.rs rename to rita_client/src/dashboard/interfaces.rs index c42b9682b..b77bd8149 100644 --- a/rita/src/rita_client/dashboard/interfaces.rs +++ b/rita_client/src/dashboard/interfaces.rs @@ -1,13 +1,11 @@ //! A generalized interface for modifying networking interface assignments using UCI -use crate::rita_common::peer_listener::unlisten_interface; -use crate::ARGS; -use crate::KI; -use crate::SETTING; use actix_web::Path; use actix_web::{HttpRequest, HttpResponse, Json}; +use failure::bail; use failure::Error; +use rita_common::peer_listener::unlisten_interface; +use rita_common::KI; use settings::FileWrite; -use settings::RitaCommonSettings; use std::collections::HashMap; use std::net::Ipv4Addr; @@ -190,17 +188,19 @@ pub fn ethernet_transform_mode( } else if a == InterfaceMode::Unknown || b == InterfaceMode::Unknown { bail!("We can't change Unknown interfaces!"); } + let rita_client = settings::get_rita_client(); + let mut network = rita_client.network; // if we have edited UCI and it fails we set this var to handle cleanup later let mut return_codes = Vec::new(); // in case of failure we revert to here - let old_network_settings = { SETTING.get_network().clone() }; + let old_network_settings = { network.clone() }; let filtered_ifname = format!("network.rita_{}", ifname.replace(".", "")); match a { // Wan is very simple, just delete it InterfaceMode::Wan | InterfaceMode::StaticWan { .. } => { - SETTING.get_network_mut().external_nic = None; + network.external_nic = None; let ret = KI.del_uci_var("network.backhaul"); return_codes.push(ret); @@ -227,7 +227,7 @@ pub fn ethernet_transform_mode( // from the config InterfaceMode::Mesh => { unlisten_interface(ifname.to_string()); - SETTING.get_network_mut().peer_interfaces.remove(ifname); + network.peer_interfaces.remove(ifname); let ret = KI.del_uci_var(&filtered_ifname); return_codes.push(ret); @@ -238,7 +238,7 @@ pub fn ethernet_transform_mode( match b { // here we add back all the properties of backhaul we removed InterfaceMode::Wan => { - SETTING.get_network_mut().external_nic = Some(ifname.to_string()); + network.external_nic = Some(ifname.to_string()); let ret = KI.set_uci_var("network.backhaul", "interface"); return_codes.push(ret); @@ -252,7 +252,7 @@ pub fn ethernet_transform_mode( ipaddr, gateway, } => { - SETTING.get_network_mut().external_nic = Some(ifname.to_string()); + network.external_nic = Some(ifname.to_string()); let ret = KI.set_uci_var("network.backhaul", "interface"); return_codes.push(ret); @@ -315,10 +315,7 @@ pub fn ethernet_transform_mode( } } InterfaceMode::Mesh => { - SETTING - .get_network_mut() - .peer_interfaces - .insert(ifname.to_string()); + network.peer_interfaces.insert(ifname.to_string()); let ret = KI.set_uci_var(&filtered_ifname, "interface"); return_codes.push(ret); @@ -337,15 +334,25 @@ pub fn ethernet_transform_mode( error_occured = true; } } + let mut rita_client = settings::get_rita_client(); + let temp_copy = rita_client.clone(); if error_occured { let res = KI.uci_revert("network"); - *SETTING.get_network_mut() = old_network_settings; + rita_client.network = old_network_settings; + settings::set_rita_client(rita_client); bail!("Error running UCI commands! Revert attempted: {:?}", res); } + rita_client.network = network; + settings::set_rita_client(rita_client); KI.uci_commit(&"network")?; KI.openwrt_reset_network()?; - SETTING.write().unwrap().write(&ARGS.flag_config)?; + + temp_copy.write(&settings::get_flag_config())?; + + if let Err(_e) = temp_copy.write(&settings::get_flag_config()) { + return Err(_e); + } // We edited disk contents, force global sync KI.fs_sync()?; diff --git a/rita/src/rita_client/dashboard/localization.rs b/rita_client/src/dashboard/localization.rs similarity index 89% rename from rita/src/rita_client/dashboard/localization.rs rename to rita_client/src/dashboard/localization.rs index c34ca140c..66325e07b 100644 --- a/rita/src/rita_client/dashboard/localization.rs +++ b/rita_client/src/dashboard/localization.rs @@ -1,4 +1,3 @@ -use crate::SETTING; use actix_web::error::JsonPayloadError; use actix_web::{client, HttpMessage, HttpRequest, HttpResponse, Json}; use althea_types::WyreReservationRequestCarrier; @@ -8,9 +7,8 @@ use futures01::future; use futures01::future::Either; use futures01::Future; use phonenumber::Mode; -use settings::client::RitaClientSettings; use settings::localization::LocalizationSettings; -use settings::RitaCommonSettings; + use std::time::Duration; /// A version of the localization struct that serializes into a more easily @@ -38,7 +36,7 @@ impl From for LocalizationReturn { pub fn get_localization(_req: HttpRequest) -> Json { debug!("/localization GET hit"); - let localization = SETTING.get_localization().clone(); + let localization = settings::get_rita_client().get_localization(); Json(localization.into()) } @@ -56,9 +54,11 @@ pub fn get_wyre_reservation( amount: Json, ) -> Box> { info!("Getting wyre reservation"); - let exit_client = SETTING.get_exit_client(); - let operator = SETTING.get_operator(); - let id = SETTING.get_identity(); + + let mut rita_client = settings::get_rita_client(); + let exit_client = rita_client.exit_client; + let operator = rita_client.operator; + let id = settings::get_rita_client().get_identity(); let payload = WyreReservationRequestCarrier { amount: amount.amount, address: None, @@ -66,7 +66,9 @@ pub fn get_wyre_reservation( contact_info: exit_client.contact_info.clone().unwrap().into(), billing_details: operator.billing_details.clone().unwrap(), }; - + rita_client.exit_client = exit_client; + rita_client.operator = operator; + settings::set_rita_client(rita_client); #[cfg(not(feature = "operator_debug"))] let api_url = "https://operator.althea.net:8080/wyre_reservation"; #[cfg(feature = "operator_debug")] diff --git a/rita/src/rita_client/dashboard/logging.rs b/rita_client/src/dashboard/logging.rs similarity index 62% rename from rita/src/rita_client/dashboard/logging.rs rename to rita_client/src/dashboard/logging.rs index 85bcb3f24..b6e46f6ef 100644 --- a/rita/src/rita_client/dashboard/logging.rs +++ b/rita_client/src/dashboard/logging.rs @@ -1,28 +1,29 @@ -use crate::ARGS; -use crate::KI; -use crate::SETTING; use actix_web::http::StatusCode; use actix_web::{HttpRequest, HttpResponse, Path}; use failure::Error; use log::LevelFilter; -use settings::client::RitaClientSettings; +use rita_common::KI; use settings::FileWrite; pub fn get_remote_logging(_req: HttpRequest) -> Result { - Ok(HttpResponse::Ok().json(SETTING.get_log().enabled)) + Ok(HttpResponse::Ok().json(settings::get_rita_client().log.enabled)) } pub fn remote_logging(path: Path) -> Result { let enabled = path.into_inner(); debug!("/remote_logging/enable/{} hit", enabled); - SETTING.get_log_mut().enabled = enabled; - // try and save the config and fail if we can't - if let Err(e) = SETTING.write().unwrap().write(&ARGS.flag_config) { + let mut rita_client = settings::get_rita_client(); + + let mut log = settings::get_rita_client().log; + log.enabled = enabled; + rita_client.log = log; + settings::set_rita_client(rita_client); + + if let Err(e) = settings::get_rita_client().write(&settings::get_flag_config()) { return Err(e); } - if let Err(e) = KI.run_command("/etc/init.d/rita", &["restart"]) { return Err(e.into()); } @@ -31,7 +32,8 @@ pub fn remote_logging(path: Path) -> Result { } pub fn get_remote_logging_level(_req: HttpRequest) -> Result { - let level = &SETTING.get_log().level; + let rita_client = settings::get_rita_client(); + let level = &rita_client.log.level; Ok(HttpResponse::Ok().json(level)) } @@ -48,11 +50,16 @@ pub fn remote_logging_level(path: Path) -> Result { } }; - SETTING.get_log_mut().level = log_level.to_string(); + let mut log = settings::get_rita_client().log; + log.level = log_level.to_string(); + let mut rita_client = settings::get_rita_client(); + rita_client.log = log; + settings::set_rita_client(rita_client); // try and save the config and fail if we can't - if let Err(e) = SETTING.write().unwrap().write(&ARGS.flag_config) { - return Err(e); + let rita_client = settings::get_rita_client(); + if let Err(_e) = rita_client.write(&settings::get_flag_config()) { + return Err(_e); } if let Err(e) = KI.run_command("/etc/init.d/rita", &["restart"]) { diff --git a/rita/src/rita_client/dashboard/mesh_ip.rs b/rita_client/src/dashboard/mesh_ip.rs similarity index 77% rename from rita/src/rita_client/dashboard/mesh_ip.rs rename to rita_client/src/dashboard/mesh_ip.rs index 2952babd6..a97eee2da 100644 --- a/rita/src/rita_client/dashboard/mesh_ip.rs +++ b/rita_client/src/dashboard/mesh_ip.rs @@ -1,6 +1,4 @@ -use crate::SETTING; -use ::actix_web::{HttpRequest, HttpResponse}; -use settings::RitaCommonSettings; +use actix_web::{HttpRequest, HttpResponse}; use std::collections::HashMap; pub fn get_mesh_ip(_req: HttpRequest) -> HttpResponse { @@ -8,7 +6,7 @@ pub fn get_mesh_ip(_req: HttpRequest) -> HttpResponse { let mut ret = HashMap::new(); - match SETTING.get_network().mesh_ip { + match settings::get_rita_client().get_network().mesh_ip { Some(ip) => { ret.insert("mesh_ip".to_owned(), format!("{}", ip)); } diff --git a/rita/src/rita_client/dashboard/mod.rs b/rita_client/src/dashboard/mod.rs similarity index 100% rename from rita/src/rita_client/dashboard/mod.rs rename to rita_client/src/dashboard/mod.rs diff --git a/rita/src/rita_client/dashboard/neighbors.rs b/rita_client/src/dashboard/neighbors.rs similarity index 92% rename from rita/src/rita_client/dashboard/neighbors.rs rename to rita_client/src/dashboard/neighbors.rs index 89bb8a892..714cf7525 100644 --- a/rita/src/rita_client/dashboard/neighbors.rs +++ b/rita_client/src/dashboard/neighbors.rs @@ -1,23 +1,18 @@ -use crate::rita_common::debt_keeper::{dump, NodeDebtData}; -use crate::rita_common::network_monitor::{GetStats, IfaceStats, NetworkMonitor, Stats}; -use crate::rita_common::tunnel_manager::{GetNeighbors, Neighbor, TunnelManager}; -use crate::SETTING; use actix::SystemService; use actix_web::AsyncResponder; use actix_web::{HttpRequest, Json}; use althea_types::Identity; use arrayvec::ArrayString; -use babel_monitor::get_installed_route; -use babel_monitor::get_route_via_neigh; -use babel_monitor::Route as RouteLegacy; +use babel_monitor::{get_installed_route, get_route_via_neigh, Route as RouteLegacy}; use babel_monitor_legacy::open_babel_stream_legacy; use babel_monitor_legacy::parse_routes_legacy; use babel_monitor_legacy::start_connection_legacy; use failure::Error; use futures01::Future; use num256::{Int256, Uint256}; -use settings::client::RitaClientSettings; -use settings::RitaCommonSettings; +use rita_common::debt_keeper::{dump, NodeDebtData}; +use rita_common::network_monitor::{GetStats, IfaceStats, NetworkMonitor, Stats}; +use rita_common::tunnel_manager::{GetNeighbors, Neighbor, TunnelManager}; use std::collections::HashMap; #[derive(Serialize)] @@ -39,7 +34,7 @@ pub struct NodeInfo { pub fn get_routes( _req: HttpRequest, ) -> Box>, Error = Error>> { - let babel_port = SETTING.get_network().babel_port; + let babel_port = settings::get_rita_client().get_network().babel_port; Box::new( open_babel_stream_legacy(babel_port) .from_err() @@ -71,7 +66,7 @@ pub fn get_neighbor_info( let combined_list = merge_debts_and_neighbors(neighbors, debts); - let babel_port = SETTING.get_network().babel_port; + let babel_port = settings::get_rita_client().get_network().babel_port; open_babel_stream_legacy(babel_port) .from_err() @@ -109,8 +104,8 @@ fn generate_neighbors_list( debts: HashMap, ) -> Vec { let mut output = Vec::new(); - - let exit_client = SETTING.get_exit_client(); + let rita_client = settings::get_rita_client(); + let exit_client = rita_client.exit_client; let current_exit = exit_client.get_current_exit(); for (identity, (debt_info, neigh)) in debts.iter() { diff --git a/rita/src/rita_client/dashboard/notifications.rs b/rita_client/src/dashboard/notifications.rs similarity index 54% rename from rita/src/rita_client/dashboard/notifications.rs rename to rita_client/src/dashboard/notifications.rs index af23211f6..d70c368fd 100644 --- a/rita/src/rita_client/dashboard/notifications.rs +++ b/rita_client/src/dashboard/notifications.rs @@ -1,12 +1,11 @@ -use crate::ARGS; -use crate::SETTING; use ::actix_web::Path; use ::actix_web::{HttpRequest, HttpResponse}; -use settings::client::RitaClientSettings; use settings::FileWrite; pub fn get_low_balance_notification(_req: HttpRequest) -> HttpResponse { - let setting = SETTING.get_exit_client().low_balance_notification; + let setting = settings::get_rita_client() + .exit_client + .low_balance_notification; HttpResponse::Ok().json(setting.to_string()) } @@ -14,11 +13,17 @@ pub fn get_low_balance_notification(_req: HttpRequest) -> HttpResponse { pub fn set_low_balance_notification(path: Path) -> HttpResponse { let value = path.into_inner(); debug!("Set low balance notification hit!"); - SETTING.get_exit_client_mut().low_balance_notification = value; + + let mut exit_client = settings::get_rita_client().exit_client; + exit_client.low_balance_notification = value; + let mut rita_client = settings::get_rita_client(); + rita_client.exit_client = exit_client; + settings::set_rita_client(rita_client); // try and save the config and fail if we can't - if let Err(_e) = SETTING.write().unwrap().write(&ARGS.flag_config) { + if let Err(_e) = settings::get_rita_client().write(&settings::get_flag_config()) { return HttpResponse::InternalServerError().finish(); } + HttpResponse::Ok().json(()) } diff --git a/rita/src/rita_client/dashboard/operator.rs b/rita_client/src/dashboard/operator.rs similarity index 56% rename from rita/src/rita_client/dashboard/operator.rs rename to rita_client/src/dashboard/operator.rs index c665064cb..92f15143f 100644 --- a/rita/src/rita_client/dashboard/operator.rs +++ b/rita_client/src/dashboard/operator.rs @@ -1,19 +1,16 @@ -use crate::rita_client::operator_fee_manager::get_operator_fee_debt; -use crate::ARGS; -use crate::SETTING; +use crate::operator_fee_manager::get_operator_fee_debt; use actix_web::Path; use actix_web::{HttpRequest, HttpResponse, Json, Result}; use clarity::Address; use failure::Error; use num256::Uint256; -use settings::client::RitaClientSettings; -use settings::FileWrite; use std::collections::HashMap; /// TODO remove after beta 12, provided for backwards compat pub fn get_dao_list(_req: HttpRequest) -> Result>, Error> { trace!("get dao list: Hit"); - match SETTING.get_operator().operator_address { + let rita_client = settings::get_rita_client(); + match rita_client.operator.operator_address { Some(address) => Ok(Json(vec![address])), None => Ok(Json(Vec::new())), } @@ -23,19 +20,26 @@ pub fn get_dao_list(_req: HttpRequest) -> Result>, Error> { pub fn add_to_dao_list(path: Path
) -> HttpResponse { trace!("Add to dao list: Hit"); let provided_address = path.into_inner(); - SETTING.get_operator_mut().operator_address = Some(provided_address); - if let Err(_e) = SETTING.write().unwrap().write(&ARGS.flag_config) { - return HttpResponse::InternalServerError().finish(); - } + let mut rita_client = settings::get_rita_client(); + let mut operator = rita_client.operator; + operator.operator_address = Some(provided_address); + + rita_client.operator = operator; + settings::set_rita_client(rita_client); + HttpResponse::Ok().finish() } /// TODO remove after beta 12, provided for backwards compat pub fn remove_from_dao_list(_path: Path
) -> HttpResponse { - SETTING.get_operator_mut().operator_address = None; - if let Err(_e) = SETTING.write().unwrap().write(&ARGS.flag_config) { - return HttpResponse::InternalServerError().finish(); - } + let mut rita_client = settings::get_rita_client(); + let mut operator = rita_client.operator; + + operator.operator_address = None; + + rita_client.operator = operator; + settings::set_rita_client(rita_client); + HttpResponse::Ok().finish() } @@ -43,7 +47,8 @@ pub fn remove_from_dao_list(_path: Path
) -> HttpResponse { pub fn get_dao_fee(_req: HttpRequest) -> HttpResponse { debug!("/dao_fee GET hit"); let mut ret = HashMap::new(); - ret.insert("dao_fee", SETTING.get_operator().operator_fee.clone()); + let rita_client = settings::get_rita_client(); + ret.insert("dao_fee", rita_client.operator.operator_fee); HttpResponse::Ok().json(ret) } @@ -52,17 +57,20 @@ pub fn get_dao_fee(_req: HttpRequest) -> HttpResponse { pub fn set_dao_fee(path: Path) -> HttpResponse { let new_fee = path.into_inner(); debug!("/dao_fee/{} POST hit", new_fee); - SETTING.get_operator_mut().operator_fee = new_fee; + let mut rita_client = settings::get_rita_client(); + let mut operator = rita_client.operator; + operator.operator_fee = new_fee; + + rita_client.operator = operator; + settings::set_rita_client(rita_client); - if let Err(_e) = SETTING.write().unwrap().write(&ARGS.flag_config) { - return HttpResponse::InternalServerError().finish(); - } HttpResponse::Ok().finish() } pub fn get_operator(_req: HttpRequest) -> Json> { trace!("get operator address: Hit"); - match SETTING.get_operator().operator_address { + let rita_client = settings::get_rita_client(); + match rita_client.operator.operator_address { Some(address) => Json(Some(address)), None => Json(None), } @@ -71,24 +79,30 @@ pub fn get_operator(_req: HttpRequest) -> Json> { pub fn change_operator(path: Path
) -> HttpResponse { trace!("add operator address: Hit"); let provided_address = path.into_inner(); - SETTING.get_operator_mut().operator_address = Some(provided_address); - if let Err(_e) = SETTING.write().unwrap().write(&ARGS.flag_config) { - return HttpResponse::InternalServerError().finish(); - } + let mut rita_client = settings::get_rita_client(); + let mut operator = rita_client.operator; + + operator.operator_address = Some(provided_address); + + rita_client.operator = operator; + settings::set_rita_client(rita_client); + HttpResponse::Ok().finish() } pub fn remove_operator(_path: Path
) -> HttpResponse { - SETTING.get_operator_mut().operator_address = None; - if let Err(_e) = SETTING.write().unwrap().write(&ARGS.flag_config) { - return HttpResponse::InternalServerError().finish(); - } + let mut rita_client = settings::get_rita_client(); + let mut operator = rita_client.operator; + operator.operator_address = None; + + rita_client.operator = operator; + settings::set_rita_client(rita_client); HttpResponse::Ok().finish() } pub fn get_operator_fee(_req: HttpRequest) -> HttpResponse { debug!("get operator GET hit"); - HttpResponse::Ok().json(SETTING.get_operator().operator_fee.clone()) + HttpResponse::Ok().json(settings::get_rita_client().operator.operator_fee) } pub fn get_operator_debt(_req: HttpRequest) -> HttpResponse { diff --git a/rita/src/rita_client/dashboard/prices.rs b/rita_client/src/dashboard/prices.rs similarity index 60% rename from rita/src/rita_client/dashboard/prices.rs rename to rita_client/src/dashboard/prices.rs index 0a32b0801..2bee692de 100644 --- a/rita/src/rita_client/dashboard/prices.rs +++ b/rita_client/src/dashboard/prices.rs @@ -1,34 +1,37 @@ -use crate::rita_client::traffic_watcher::GetExitDestPrice; -use crate::rita_client::traffic_watcher::TrafficWatcher; -use crate::ARGS; -use crate::SETTING; +use crate::traffic_watcher::GetExitDestPrice; +use crate::traffic_watcher::TrafficWatcher; + use actix::SystemService; use actix_web::Path; use actix_web::{HttpRequest, HttpResponse, Json, Result}; use failure::Error; use futures01::Future; use num256::Uint256; -use settings::client::RitaClientSettings; use settings::FileWrite; -use settings::RitaCommonSettings; - pub fn auto_pricing_status(_req: HttpRequest) -> Result, Error> { debug!("Get Auto pricing enabled hit!"); - Ok(Json(SETTING.get_operator().use_operator_price)) + Ok(Json( + settings::get_rita_client().operator.use_operator_price, + )) } pub fn set_auto_pricing(path: Path) -> Result { let value = path.into_inner(); debug!("Set Auto pricing enabled hit!"); - let mut op = SETTING.get_operator_mut(); + let mut rita_client = settings::get_rita_client(); + let mut op = rita_client.operator; if !op.force_use_operator_price { op.use_operator_price = value; } - drop(op); + rita_client.operator = op; + settings::set_rita_client(rita_client); // try and save the config and fail if we can't - if let Err(e) = SETTING.write().unwrap().write(&ARGS.flag_config) { - return Err(e); + let rita_client = settings::get_rita_client(); + if let Err(_e) = rita_client.write(&settings::get_flag_config()) { + return Err(_e); + } else { + settings::set_rita_client(rita_client); } Ok(HttpResponse::Ok().json(())) } @@ -42,11 +45,13 @@ pub struct Prices { pub fn get_prices(_req: HttpRequest) -> Box, Error = Error>> { debug!("/prices GET hit"); + + let payment = settings::get_rita_client().payment; let f = TrafficWatcher::from_registry().send(GetExitDestPrice); - let b = f.from_err().and_then(|exit_dest_price| { + let b = f.from_err().and_then(move |exit_dest_price| { let exit_dest_price = exit_dest_price.unwrap(); - let simulated_tx_fee = SETTING.get_payment().simulated_transaction_fee; - let operator_fee = SETTING.get_operator().operator_fee.clone(); + let simulated_tx_fee = payment.simulated_transaction_fee; + let operator_fee = settings::get_rita_client().operator.operator_fee; let p = Prices { exit_dest_price, dao_fee: operator_fee, @@ -54,5 +59,6 @@ pub fn get_prices(_req: HttpRequest) -> Box, Erro }; Ok(Json(p)) }); + Box::new(b) } diff --git a/rita/src/rita_client/dashboard/release_feed.rs b/rita_client/src/dashboard/release_feed.rs similarity index 86% rename from rita/src/rita_client/dashboard/release_feed.rs rename to rita_client/src/dashboard/release_feed.rs index 7a6692412..4d94eada6 100644 --- a/rita/src/rita_client/dashboard/release_feed.rs +++ b/rita_client/src/dashboard/release_feed.rs @@ -1,5 +1,3 @@ -use crate::KI; -use crate::SETTING; use actix_web::http::StatusCode; use actix_web::HttpRequest; use actix_web::HttpResponse; @@ -7,7 +5,7 @@ use actix_web::Path; use althea_kernel_interface::opkg_feeds::get_release_feed; use althea_kernel_interface::opkg_feeds::set_release_feed; use failure::Error; -use settings::RitaCommonSettings; +use rita_common::KI; pub fn get_release_feed_http(_req: HttpRequest) -> Result { if !KI.is_openwrt() { @@ -38,7 +36,10 @@ pub fn set_release_feed_http(path: Path) -> HttpResponse { .json(format!("Failed to write new release feed with {:?}", e)); } - let mut settings = SETTING.get_network_mut(); + let mut rita_client = settings::get_rita_client(); + let mut settings = rita_client.network; settings.user_set_release_feed = true; + rita_client.network = settings; + settings::set_rita_client(rita_client); HttpResponse::Ok().json(()) } diff --git a/rita/src/rita_client/dashboard/remote_access.rs b/rita_client/src/dashboard/remote_access.rs similarity index 99% rename from rita/src/rita_client/dashboard/remote_access.rs rename to rita_client/src/dashboard/remote_access.rs index af7f1c9d8..b818cac6c 100644 --- a/rita/src/rita_client/dashboard/remote_access.rs +++ b/rita_client/src/dashboard/remote_access.rs @@ -1,11 +1,12 @@ -use crate::KI; use actix_web::http::StatusCode; use actix_web::HttpRequest; use actix_web::HttpResponse; use actix_web::Path; use althea_kernel_interface::file_io::get_lines; use althea_kernel_interface::file_io::write_out; +use failure::format_err; use failure::Error; +use rita_common::KI; static DROPBEAR_CONFIG: &str = "/etc/config/dropbear"; static FIREWALL_CONFIG: &str = "/etc/config/firewall"; diff --git a/rita/src/rita_client/dashboard/router.rs b/rita_client/src/dashboard/router.rs similarity index 96% rename from rita/src/rita_client/dashboard/router.rs rename to rita_client/src/dashboard/router.rs index 4e982a0de..ca6dfbaa5 100644 --- a/rita/src/rita_client/dashboard/router.rs +++ b/rita_client/src/dashboard/router.rs @@ -1,6 +1,6 @@ -use crate::KI; use actix_web::{HttpRequest, HttpResponse}; use failure::Error; +use rita_common::KI; pub fn reboot_router(_req: HttpRequest) -> Result { if KI.is_openwrt() { diff --git a/rita/src/rita_client/dashboard/system_chain.rs b/rita_client/src/dashboard/system_chain.rs similarity index 84% rename from rita/src/rita_client/dashboard/system_chain.rs rename to rita_client/src/dashboard/system_chain.rs index d240c2520..0f88c42e1 100644 --- a/rita/src/rita_client/dashboard/system_chain.rs +++ b/rita_client/src/dashboard/system_chain.rs @@ -1,8 +1,6 @@ -use crate::ARGS; -use crate::SETTING; -use ::actix_web::http::StatusCode; -use ::actix_web::Path; -use ::actix_web::{HttpRequest, HttpResponse}; +use actix_web::http::StatusCode; +use actix_web::Path; +use actix_web::{HttpRequest, HttpResponse}; use althea_types::SystemChain; use failure::Error; use settings::payment::PaymentSettings; @@ -13,7 +11,6 @@ use settings::payment::XDAI_FEE_MULTIPLIER; use settings::payment::XDAI_MAX_GAS; use settings::payment::XDAI_MIN_GAS; use settings::FileWrite; -use settings::RitaCommonSettings; /// Changes the full node configuration value between test/prod and other networks pub fn set_system_blockchain_endpoint(path: Path) -> Result { @@ -25,13 +22,18 @@ pub fn set_system_blockchain_endpoint(path: Path) -> Result) -> Result Result { debug!("/blockchain/ GET hit"); - Ok(HttpResponse::Ok().json(SETTING.get_payment().system_chain)) + Ok(HttpResponse::Ok().json(settings::get_rita_client().payment.system_chain)) } pub fn set_system_blockchain(id: SystemChain, payment: &mut PaymentSettings) { diff --git a/rita/src/rita_client/dashboard/usage.rs b/rita_client/src/dashboard/usage.rs similarity index 62% rename from rita/src/rita_client/dashboard/usage.rs rename to rita_client/src/dashboard/usage.rs index a67f2a7f5..667d8f04e 100644 --- a/rita/src/rita_client/dashboard/usage.rs +++ b/rita_client/src/dashboard/usage.rs @@ -1,8 +1,8 @@ -use crate::rita_common::usage_tracker::handle_usage_data; -use crate::rita_common::usage_tracker::GetUsage; -use crate::rita_common::usage_tracker::UsageHour; -use crate::rita_common::usage_tracker::UsageType; -use ::actix_web::{HttpRequest, Json}; +use actix_web::{HttpRequest, Json}; +use rita_common::usage_tracker::handle_usage_data; +use rita_common::usage_tracker::GetUsage; +use rita_common::usage_tracker::UsageHour; +use rita_common::usage_tracker::UsageType; use std::collections::VecDeque; pub fn get_client_usage(_req: HttpRequest) -> Json> { diff --git a/rita/src/rita_client/dashboard/wifi.rs b/rita_client/src/dashboard/wifi.rs similarity index 98% rename from rita/src/rita_client/dashboard/wifi.rs rename to rita_client/src/dashboard/wifi.rs index e2ef1c20d..7f72a47d6 100644 --- a/rita/src/rita_client/dashboard/wifi.rs +++ b/rita_client/src/dashboard/wifi.rs @@ -1,14 +1,13 @@ //! These endpoints are used to modify mundane wireless settings -use crate::rita_common::dashboard::nickname::maybe_set_nickname; -use crate::KI; -use crate::SETTING; +use rita_common::dashboard::nickname::maybe_set_nickname; +use rita_common::KI; + use ::actix_web::http::StatusCode; use ::actix_web::Path; use ::actix_web::{HttpRequest, HttpResponse, Json}; use failure::Error; use serde_json::Value; -use settings::RitaCommonSettings; use std::collections::HashMap; /// legal in the US and around the world, don't allow odd channels @@ -250,7 +249,7 @@ fn validate_channel( let channel_width_is_40 = channel_width.contains("40"); let channel_width_is_80 = channel_width.contains("80"); let channel_width_is_160 = channel_width.contains("160"); - let model = SETTING.get_network().device.clone(); + let model = settings::get_rita_client().get_network().device; // trying to swap from 5ghz to 2.4ghz or vice versa, usually this // is impossible, although some multifunction cards allow it if (old_is_two && new_is_five) || (old_is_five && new_is_two) { @@ -306,7 +305,7 @@ pub fn get_allowed_wifi_channels(radio: Path) -> Result Result<(), Error> { - KI.update_settings_route(&mut SETTING.get_network_mut().last_default_route); + let mut rita_client = settings::get_rita_client(); + let mut network = rita_client.network; + // TODO this should be refactored to return a value + KI.update_settings_route(&mut network.last_default_route); if let Err(KernelInterfaceError::RuntimeError(v)) = KI.setup_wg_if_named("wg_exit") { return Err(format_err!("{}", v)); @@ -69,14 +69,17 @@ fn linux_setup_exit_tunnel( let args = ClientExitTunnelConfig { endpoint: SocketAddr::new(current_exit.id.mesh_ip, general_details.wg_exit_port), pubkey: current_exit.id.wg_public_key, - private_key_path: SETTING.get_network().wg_private_key_path.clone(), - listen_port: SETTING.get_exit_client().wg_listen_port, + private_key_path: network.wg_private_key_path.clone(), + listen_port: rita_client.exit_client.wg_listen_port, local_ip: our_details.client_internal_ip, netmask: general_details.netmask, - rita_hello_port: SETTING.get_network().rita_hello_port, - user_specified_speed: SETTING.get_network().user_bandwidth_limit, + rita_hello_port: network.rita_hello_port, + user_specified_speed: network.user_bandwidth_limit, }; + rita_client.network = network; + settings::set_rita_client(rita_client); + KI.set_client_exit_tunnel_config(args)?; KI.set_route_to_tunnel(&general_details.server_internal_ip)?; @@ -117,19 +120,19 @@ fn encrypt_exit_client_id( exit_pubkey: &PublicKey, id: ExitClientIdentity, ) -> EncryptedExitClientIdentity { - let network_settings = SETTING.get_network(); + let network_settings = settings::get_rita_client().network; let our_publickey = network_settings.wg_public_key.expect("No public key?"); let our_secretkey = network_settings .wg_private_key .expect("No private key?") .into(); - drop(network_settings); let plaintext = serde_json::to_string(&id) .expect("Failed to serialize ExitState!") .into_bytes(); let nonce = box_::gen_nonce(); let ciphertext = box_::seal(&plaintext, &nonce, exit_pubkey, &our_secretkey); + EncryptedExitClientIdentity { nonce: nonce.0, pubkey: our_publickey, @@ -141,12 +144,12 @@ fn decrypt_exit_state( exit_state: EncryptedExitState, exit_pubkey: PublicKey, ) -> Result { - let network_settings = SETTING.get_network(); + let rita_client = settings::get_rita_client(); + let network_settings = rita_client.network; let our_secretkey = network_settings .wg_private_key .expect("No private key?") .into(); - drop(network_settings); let ciphertext = exit_state.encrypted_exit_state; let nonce = Nonce(exit_state.nonce); let decrypted_exit_state: ExitState = @@ -230,7 +233,7 @@ fn send_exit_status_request( } fn exit_general_details_request(exit: String) -> impl Future { - let current_exit = match SETTING.get_exits().get(&exit) { + let current_exit = match settings::get_rita_client().exit_client.exits.get(&exit) { Some(current_exit) => current_exit.clone(), None => { return Box::new(future::err(format_err!("No valid exit for {}", exit))) @@ -241,17 +244,15 @@ fn exit_general_details_request(exit: String) -> impl Future exit, None => bail!("Could not find exit {}", exit), }; - current_exit.info = exit_details; + settings::set_rita_client(rita_client); Ok(()) }); @@ -262,7 +263,8 @@ pub fn exit_setup_request( exit: String, code: Option, ) -> Box> { - let current_exit = match SETTING.get_exits().get(&exit) { + let exit_client = settings::get_rita_client().exit_client; + let current_exit = match exit_client.exits.get(&exit) { Some(exit_struct) => exit_struct.clone(), None => return Box::new(future::err(format_err!("Could not find exit {:?}", exit))), }; @@ -274,7 +276,7 @@ pub fn exit_setup_request( }; let mut reg_details: ExitRegistrationDetails = - match SETTING.get_exit_client().contact_info.clone() { + match settings::get_rita_client().exit_client.contact_info { Some(val) => val.into(), None => { if let ExitVerifMode::Off = exit_auth_type { @@ -301,7 +303,7 @@ pub fn exit_setup_request( } let ident = ExitClientIdentity { - global: match SETTING.get_identity() { + global: match settings::get_rita_client().get_identity() { Some(id) => id, None => { return Box::new(future::err(format_err!( @@ -309,7 +311,7 @@ pub fn exit_setup_request( ))); } }, - wg_port: SETTING.get_exit_client().wg_listen_port, + wg_port: exit_client.wg_listen_port, reg_details, }; @@ -326,16 +328,15 @@ pub fn exit_setup_request( send_exit_setup_request(exit_pubkey, &endpoint, ident) .from_err() .and_then(move |exit_response| { - let mut exits = SETTING.get_exits_mut(); + let mut rita_client = settings::get_rita_client(); - let current_exit = match exits.get_mut(&exit) { + let current_exit = match rita_client.exit_client.exits.get_mut(&exit) { Some(exit_struct) => exit_struct, None => bail!("Could not find exit {:?}", exit), }; - current_exit.info = exit_response.clone(); - - trace!("Got exit setup response {:?}", exit_response); + current_exit.info = exit_response; + settings::set_rita_client(rita_client); Ok(()) }), @@ -343,14 +344,14 @@ pub fn exit_setup_request( } fn exit_status_request(exit: String) -> impl Future { - let current_exit = match SETTING.get_exits().get(&exit) { + let current_exit = match settings::get_rita_client().exit_client.exits.get(&exit) { Some(current_exit) => current_exit.clone(), None => { return Box::new(future::err(format_err!("No valid exit for {}", exit))) as Box>; } }; - let reg_details = match SETTING.get_exit_client().contact_info.clone() { + let reg_details = match settings::get_rita_client().exit_client.contact_info { Some(val) => val.into(), None => return Box::new(future::err(format_err!("No valid details"))), }; @@ -358,7 +359,7 @@ fn exit_status_request(exit: String) -> impl Future { let exit_server = current_exit.id.mesh_ip; let exit_pubkey = current_exit.id.wg_public_key; let ident = ExitClientIdentity { - global: match SETTING.get_identity() { + global: match settings::get_rita_client().get_identity() { Some(id) => id, None => { return Box::new(future::err(format_err!( @@ -366,7 +367,7 @@ fn exit_status_request(exit: String) -> impl Future { ))); } }, - wg_port: SETTING.get_exit_client().wg_listen_port, + wg_port: settings::get_rita_client().exit_client.wg_listen_port, reg_details, }; @@ -380,19 +381,21 @@ fn exit_status_request(exit: String) -> impl Future { let r = send_exit_status_request(exit_pubkey, &endpoint, ident).and_then(move |exit_response| { - let mut exits = SETTING.get_exits_mut(); + let mut rita_client = settings::get_rita_client(); - let current_exit = match exits.get_mut(&exit) { + let current_exit = match rita_client.exit_client.exits.get_mut(&exit) { Some(exit_struct) => exit_struct, None => bail!("Could not find exit {:?}", exit), }; current_exit.info = exit_response.clone(); + settings::set_rita_client(rita_client); trace!("Got exit status response {:?}", exit_response); Ok(()) }); + Box::new(r) } @@ -430,8 +433,14 @@ impl Handler for ExitManager { // scopes our access to SETTING and prevent // holding a readlock while exit tunnel setup requires a write lock // roughly the same as a drop(); inline - let client_can_use_free_tier = { SETTING.get_payment().client_can_use_free_tier }; - let exit_server = { SETTING.get_exit_client().get_current_exit().cloned() }; + let client_can_use_free_tier = + { settings::get_rita_client().payment.client_can_use_free_tier }; + let exit_server = { + settings::get_rita_client() + .exit_client + .get_current_exit() + .cloned() + }; // code that connects to the current exit server trace!("About to setup exit tunnel!"); @@ -511,7 +520,7 @@ impl Handler for ExitManager { let exit_internal_addr = general_details.server_internal_ip; let exit_port = exit.registration_port; let exit_id = exit.id; - let babel_port = SETTING.get_network().babel_port; + let babel_port = settings::get_rita_client().network.babel_port; trace!("We are signed up for the selected exit!"); Arbiter::spawn( @@ -544,7 +553,7 @@ impl Handler for ExitManager { } // code that manages requesting details to exits - let servers = { SETTING.get_exits().clone() }; + let servers = { settings::get_rita_client().exit_client.exits }; let mut futs: Vec>> = Vec::new(); diff --git a/rita/src/rita_client/heartbeat/mod.rs b/rita_client/src/heartbeat/mod.rs similarity index 89% rename from rita/src/rita_client/heartbeat/mod.rs rename to rita_client/src/heartbeat/mod.rs index 55ef866c0..8382928fa 100644 --- a/rita/src/rita_client/heartbeat/mod.rs +++ b/rita_client/src/heartbeat/mod.rs @@ -13,25 +13,23 @@ //! This packet is encrypted using the usual LibSodium box construction and sent to the heartbeat server in the following format //! WgKey, Nonce, Ciphertext for the HeartBeatMessage. This consumes 32 bytes, 24 bytes, and to the end of the message -use crate::rita_client::rita_loop::CLIENT_LOOP_TIMEOUT; -use crate::rita_common::network_monitor::GetNetworkInfo; -use crate::rita_common::network_monitor::NetworkMonitor; -use crate::rita_common::tunnel_manager::Neighbor as RitaNeighbor; -use crate::SETTING; +use crate::rita_loop::CLIENT_LOOP_TIMEOUT; +use babel_monitor::get_installed_route; +use babel_monitor::get_neigh_given_route; +use rita_common::network_monitor::GetNetworkInfo; +use rita_common::network_monitor::NetworkMonitor; +use rita_common::tunnel_manager::Neighbor as RitaNeighbor; + use actix::actors::resolver; use actix::{Arbiter, SystemService}; use althea_types::HeartbeatMessage; use althea_types::Identity; use althea_types::WgKey; -use babel_monitor::get_installed_route; -use babel_monitor::get_neigh_given_route; use babel_monitor::Neighbor as NeighborLegacy; use babel_monitor::Route as RouteLegacy; use failure::Error; use futures01::future::Future; use settings::client::ExitServer; -use settings::client::RitaClientSettings; -use settings::RitaCommonSettings; use sodiumoxide::crypto::box_; use std::collections::VecDeque; use std::net::{SocketAddr, UdpSocket}; @@ -79,16 +77,18 @@ pub fn send_udp_heartbeat() { .send(GetNetworkInfo {}) .timeout(CLIENT_LOOP_TIMEOUT); // Check for the basics first, before doing any of the hard futures work - let (our_id, selected_exit_details) = - if let (Some(id), Some(exit)) = (SETTING.get_identity(), get_selected_exit()) { - let exit_info = exit.info; - match exit_info.general_details() { - Some(details) => (id, details.clone()), - None => return, - } - } else { - return; - }; + let (our_id, selected_exit_details) = if let (Some(id), Some(exit)) = ( + settings::get_rita_client().get_identity(), + get_selected_exit(), + ) { + let exit_info = exit.info; + match exit_info.general_details() { + Some(details) => (id, details.clone()), + None => return, + } + } else { + return; + }; trace!("we have heartbeat basic info"); let res = dns_request.join(network_info).then(move |res| { @@ -172,7 +172,8 @@ pub fn send_udp_heartbeat() { } fn get_selected_exit_route(route_dump: &[RouteLegacy]) -> Result { - let exit_client = SETTING.get_exit_client(); + let rita_client = settings::get_rita_client(); + let exit_client = rita_client.exit_client; let exit_mesh_ip = if let Some(e) = exit_client.get_current_exit() { e.id.mesh_ip } else { @@ -182,7 +183,8 @@ fn get_selected_exit_route(route_dump: &[RouteLegacy]) -> Result Option { - let exit_client = SETTING.get_exit_client(); + let rita_client = settings::get_rita_client(); + let exit_client = rita_client.exit_client; let exit = exit_client.get_current_exit()?; Some(exit.clone()) } @@ -220,8 +222,11 @@ fn send_udp_heartbeat_packet( exit_neighbor_id: Identity, ) { trace!("building heartbeat packet"); - let network_settings = SETTING.get_network(); - let low_balance_notification = SETTING.get_exit_client().low_balance_notification; + let rita_client = settings::get_rita_client(); + let network_settings = rita_client.network; + let low_balance_notification = settings::get_rita_client() + .exit_client + .low_balance_notification; let our_publickey = network_settings.wg_public_key.expect("No public key?"); let our_secretkey = network_settings .wg_private_key @@ -245,11 +250,12 @@ fn send_udp_heartbeat_packet( }; trace!("Sending heartbeat to {:?}", remote_ip); - + let mut rita_client = settings::get_rita_client(); + let payment = rita_client.payment; let message = HeartbeatMessage { id: our_id, - organizer_address: SETTING.get_operator().operator_address, - balance: SETTING.get_payment().balance.clone(), + organizer_address: settings::get_rita_client().operator.operator_address, + balance: payment.balance.clone(), exit_dest_price: exit_price + exit_route.price as u64, upstream_id: exit_neighbor_id, exit_route, @@ -278,4 +284,6 @@ fn send_udp_heartbeat_packet( Ok(bytes) => info!("Sent {} heartbeat bytes", bytes), Err(e) => error!("Failed to send heartbeat with {:?}", e), } + rita_client.payment = payment; + settings::set_rita_client(rita_client); } diff --git a/rita_client/src/lib.rs b/rita_client/src/lib.rs new file mode 100644 index 000000000..137f0c4c7 --- /dev/null +++ b/rita_client/src/lib.rs @@ -0,0 +1,43 @@ +#[macro_use] +extern crate log; + +#[macro_use] +extern crate lazy_static; + +#[macro_use] +extern crate serde_derive; +#[macro_use] +extern crate failure; + +pub mod dashboard; +pub mod exit_manager; +pub mod heartbeat; +pub mod light_client_manager; +pub mod logging; +pub mod operator_fee_manager; +pub mod operator_update; +pub mod rita_loop; +pub mod traffic_watcher; + +pub use crate::dashboard::auth::*; +pub use crate::dashboard::backup_created::*; +pub use crate::dashboard::bandwidth_limit::*; +pub use crate::dashboard::contact_info::*; +pub use crate::dashboard::contact_info::*; +pub use crate::dashboard::eth_private_key::*; +pub use crate::dashboard::exits::*; +pub use crate::dashboard::installation_details::*; +pub use crate::dashboard::interfaces::*; +pub use crate::dashboard::localization::*; +pub use crate::dashboard::logging::*; +pub use crate::dashboard::mesh_ip::*; +pub use crate::dashboard::neighbors::*; +pub use crate::dashboard::notifications::*; +pub use crate::dashboard::operator::*; +pub use crate::dashboard::prices::*; +pub use crate::dashboard::release_feed::*; +pub use crate::dashboard::remote_access::*; +pub use crate::dashboard::router::*; +pub use crate::dashboard::system_chain::*; +pub use crate::dashboard::usage; +pub use crate::dashboard::wifi::*; diff --git a/rita/src/rita_client/light_client_manager/mod.rs b/rita_client/src/light_client_manager/mod.rs similarity index 95% rename from rita/src/rita_client/light_client_manager/mod.rs rename to rita_client/src/light_client_manager/mod.rs index f1667d444..efb63a33a 100644 --- a/rita/src/rita_client/light_client_manager/mod.rs +++ b/rita_client/src/light_client_manager/mod.rs @@ -4,17 +4,17 @@ //! especially since the client traffic exits unencrypted at one point on the participating Rita Client router. Sadly this is unavoidable as //! far as I can tell due to the restrictive nature of how and when Android allows ipv6 routing. -use crate::rita_client::traffic_watcher::GetExitDestPrice; -use crate::rita_client::traffic_watcher::TrafficWatcher; -use crate::rita_common::debt_keeper::traffic_update; -use crate::rita_common::debt_keeper::Traffic; -use crate::rita_common::peer_listener::Peer; -use crate::rita_common::tunnel_manager::id_callback::IdentityCallback; -use crate::rita_common::tunnel_manager::Tunnel; -use crate::rita_common::tunnel_manager::TunnelManager; -use crate::rita_common::utils::ip_increment::incrementv4; -use crate::KI; -use crate::SETTING; +use crate::traffic_watcher::GetExitDestPrice; +use crate::traffic_watcher::TrafficWatcher; +use rita_common::debt_keeper::traffic_update; +use rita_common::debt_keeper::Traffic; +use rita_common::peer_listener::Peer; +use rita_common::tunnel_manager::id_callback::IdentityCallback; +use rita_common::tunnel_manager::Tunnel; +use rita_common::tunnel_manager::TunnelManager; +use rita_common::utils::ip_increment::incrementv4; +use rita_common::KI; + use actix::{Actor, Context, Handler, Message, Supervised, SystemService}; use actix_web::http::StatusCode; use actix_web::{HttpRequest, HttpResponse, Json}; @@ -24,7 +24,6 @@ use althea_types::{Identity, LightClientLocalIdentity, LocalIdentity, WgKey}; use failure::Error; use futures01::future::Either; use futures01::{future, Future}; -use settings::RitaCommonSettings; use std::boxed::Box; use std::collections::HashMap; use std::collections::HashSet; @@ -157,7 +156,7 @@ pub fn light_client_hello_response( }; let lci = LightClientLocalIdentity { - global: match SETTING.get_identity() { + global: match settings::get_rita_client().get_identity() { Some(id) => id, None => { return Err(format_err!( @@ -168,7 +167,7 @@ pub fn light_client_hello_response( wg_port: tunnel.listen_port, have_tunnel: Some(have_tunnel), tunnel_address: light_client_address, - price: SETTING.get_payment().light_client_fee as u128 + price: settings::get_rita_client().payment.light_client_fee as u128 + exit_dest_price, }; // Two bools -> 4 state truth table, in 3 of @@ -338,7 +337,8 @@ impl Handler for LightClientManager { fn handle(&mut self, msg: Watch, _: &mut Context) -> Self::Result { trace!("Starting light client traffic watcher"); - let our_price = SETTING.get_payment().light_client_fee as u128 + msg.exit_dest_price; + let our_price = + settings::get_rita_client().payment.light_client_fee as u128 + msg.exit_dest_price; let tunnels = msg.tunnels; let mut debts: HashMap = HashMap::new(); for tunnel in tunnels.iter() { @@ -387,9 +387,9 @@ fn subtract_or_insert_and_subtract(data: &mut HashMap, i: Identi #[cfg(test)] mod tests { use super::*; - use crate::rita_common::tunnel_manager::tests::get_test_id; - use crate::rita_common::tunnel_manager::tests::get_test_tunnel; use clu::generate_mesh_ip; + use rita_common::tunnel_manager::get_test_id; + use rita_common::tunnel_manager::get_test_tunnel; fn get_random_id() -> Identity { Identity { diff --git a/rita/src/rita_client/mod.rs b/rita_client/src/logging.rs similarity index 79% rename from rita/src/rita_client/mod.rs rename to rita_client/src/logging.rs index 177f250a8..b62f30cc7 100644 --- a/rita/src/rita_client/mod.rs +++ b/rita_client/src/logging.rs @@ -1,27 +1,16 @@ -pub mod dashboard; -pub mod exit_manager; -pub mod heartbeat; -pub mod light_client_manager; -pub mod operator_fee_manager; -pub mod operator_update; -pub mod rita_loop; -pub mod traffic_watcher; - -use crate::SETTING; use compressed_log::builder::LoggerBuilder; use compressed_log::compression::Compression; -use failure::Error; +use failure::{bail, format_err, Error}; use log::LevelFilter; use log::Record; -use settings::client::RitaClientSettings; -use settings::RitaCommonSettings; /// enables remote logging if the user has configured it pub fn enable_remote_logging() -> Result<(), Error> { trace!("About to enable remote logging"); - let log = SETTING.get_log(); - let key = SETTING - .get_network() + let rita_client = settings::get_rita_client(); + let log = rita_client.log; + let key = rita_client + .network .wg_public_key .expect("Tried to init remote logging without WgKey!"); let logging_url = &log.dest_url; diff --git a/rita/src/rita_client/operator_fee_manager/mod.rs b/rita_client/src/operator_fee_manager/mod.rs similarity index 92% rename from rita/src/rita_client/operator_fee_manager/mod.rs rename to rita_client/src/operator_fee_manager/mod.rs index d85e3cc40..38ccda6e1 100644 --- a/rita/src/rita_client/operator_fee_manager/mod.rs +++ b/rita_client/src/operator_fee_manager/mod.rs @@ -14,12 +14,12 @@ //! will need to be re-written to better reflect a normal billing system at some point, perhaps //! querying an API for an individual bill. As this is not designed to be a trustless payment -use crate::rita_common::payment_controller::TRANSACTION_SUBMISSION_TIMEOUT; -use crate::rita_common::rita_loop::get_web3_server; -use crate::rita_common::simulated_txfee_manager::add_tx_to_total; -use crate::rita_common::usage_tracker::handle_payment_data; -use crate::rita_common::usage_tracker::UpdatePayments; -use crate::SETTING; +use rita_common::payment_controller::TRANSACTION_SUBMISSION_TIMEOUT; +use rita_common::rita_loop::get_web3_server; +use rita_common::simulated_txfee_manager::add_tx_to_total; +use rita_common::usage_tracker::handle_payment_data; +use rita_common::usage_tracker::UpdatePayments; + use ::actix::{Actor, Arbiter, Context, Handler, Message, Supervised, SystemService}; use althea_types::Identity; use althea_types::PaymentTx; @@ -27,8 +27,6 @@ use clarity::Transaction; use futures01::future::Future; use num256::Int256; use num256::Uint256; -use settings::client::RitaClientSettings; -use settings::RitaCommonSettings; use std::sync::{Arc, RwLock}; use std::time::Instant; use web30::client::Web3; @@ -112,10 +110,11 @@ impl Handler for OperatorFeeManager { fn handle(&mut self, _msg: Tick, _: &mut Context) -> Self::Result { // get variables - let operator_settings = SETTING.get_operator(); - let payment_settings = SETTING.get_payment(); + let mut rita_client = settings::get_rita_client(); + let operator_settings = rita_client.operator; + let payment_settings = rita_client.payment; let eth_private_key = payment_settings.eth_private_key; - let our_id = match SETTING.get_identity() { + let our_id = match settings::get_rita_client().get_identity() { Some(id) => id, None => return, }; @@ -147,7 +146,6 @@ impl Handler for OperatorFeeManager { let should_pay = amount_to_pay.to_int256().unwrap_or_else(|| Int256::from(0)) > pay_threshold && amount_to_pay <= our_balance; - drop(payment_settings); trace!("We should pay our operator {}", should_pay); if should_pay { @@ -222,5 +220,8 @@ impl Handler for OperatorFeeManager { } })); } + rita_client.operator = operator_settings; + rita_client.payment = payment_settings; + settings::set_rita_client(rita_client); } } diff --git a/rita/src/rita_client/operator_update/mod.rs b/rita_client/src/operator_update/mod.rs similarity index 87% rename from rita/src/rita_client/operator_update/mod.rs rename to rita_client/src/operator_update/mod.rs index 8a8868faa..e841b4f23 100644 --- a/rita/src/rita_client/operator_update/mod.rs +++ b/rita_client/src/operator_update/mod.rs @@ -1,30 +1,28 @@ //! This module is responsible for checking in with the operator server and getting updated local settings +use crate::dashboard::system_chain::set_system_blockchain; +use crate::dashboard::wifi::reset_wifi_pass; +use crate::rita_loop::is_gateway_client; +use crate::rita_loop::CLIENT_LOOP_TIMEOUT; +use rita_common::rita_loop::is_gateway; +use rita_common::tunnel_manager::neighbor_status::get_neighbor_status; +use rita_common::tunnel_manager::shaping::flag_reset_shaper; +use rita_common::utils::option_convert; -use crate::rita_client::dashboard::system_chain::set_system_blockchain; -use crate::rita_client::dashboard::wifi::reset_wifi_pass; -use crate::rita_client::rita_loop::is_gateway_client; -use crate::rita_client::rita_loop::CLIENT_LOOP_TIMEOUT; -use crate::rita_common::rita_loop::is_gateway; -use crate::rita_common::tunnel_manager::neighbor_status::get_neighbor_status; -use crate::rita_common::tunnel_manager::shaping::flag_reset_shaper; -use crate::rita_common::utils::option_convert; -use crate::KI; -use crate::SETTING; use actix::{Actor, Arbiter, Context, Handler, Message, Supervised, SystemService}; use actix_web::Error; use actix_web::{client, HttpMessage}; use althea_kernel_interface::hardware_info::get_hardware_info; use althea_kernel_interface::opkg_feeds::get_release_feed; use althea_kernel_interface::opkg_feeds::set_release_feed; + use althea_types::OperatorAction; use althea_types::OperatorCheckinMessage; use althea_types::{OperatorUpdateMessage, ReleaseStatus}; use futures01::Future; use num256::Uint256; +use rita_common::KI; use serde_json::Map; use serde_json::Value; -use settings::client::RitaClientSettings; -use settings::RitaCommonSettings; use std::sync::{Arc, RwLock}; use std::time::{Duration, Instant}; @@ -41,6 +39,13 @@ const FORBIDDEN_MERGE_VALUES: [&str; 5] = [ pub struct UptimeStruct { pub prev_time: Duration, } +impl Default for UptimeStruct { + fn default() -> Self { + UptimeStruct { + prev_time: Duration::new(0, 0), + } + } +} impl UptimeStruct { pub fn new() -> UptimeStruct { UptimeStruct { @@ -124,9 +129,11 @@ fn checkin() { #[cfg(feature = "operator_debug")] let url = "http://192.168.10.2:8080/checkin"; - let logging_enabled = SETTING.get_log().enabled; - let operator_settings = SETTING.get_operator(); - let system_chain = SETTING.get_payment().system_chain; + let mut rita_client = settings::get_rita_client(); + + let logging_enabled = rita_client.log.enabled; + let operator_settings = rita_client.operator; + let system_chain = rita_client.payment.system_chain; let operator_address = operator_settings.operator_address; let use_operator_price = operator_settings.use_operator_price || operator_settings.force_use_operator_price; @@ -134,15 +141,19 @@ fn checkin() { // exit as a mesh client, even if the is_gateway var mostly governs things related to WAN use. // So we accept either of these conditions being true. let is_gateway = is_gateway() || is_gateway_client(); - let id = SETTING.get_identity().unwrap(); + let id = settings::get_rita_client().get_identity().unwrap(); - let contact_info = option_convert(SETTING.get_exit_client().contact_info.clone()); + let contact_info = option_convert(rita_client.exit_client.contact_info.clone()); let install_details = operator_settings.installation_details.clone(); let billing_details = operator_settings.billing_details.clone(); - let user_bandwidth_limit = SETTING.get_network().user_bandwidth_limit; - let user_set_release_feed = SETTING.get_network().user_set_release_feed; + let user_bandwidth_limit = settings::get_rita_client() + .get_network() + .user_bandwidth_limit; + let user_set_release_feed = settings::get_rita_client() + .get_network() + .user_set_release_feed; - drop(operator_settings); + rita_client.operator = operator_settings; // if the user has disabled logging and has no operator configured we don't check in // if the user configures an operator but has disabled logging then we assume they still @@ -166,13 +177,14 @@ fn checkin() { neighbor_info.push(status); } - let hardware_info = match get_hardware_info(SETTING.get_network().device.clone()) { + let hardware_info = match get_hardware_info(rita_client.get_network().device) { Ok(info) => Some(info), Err(e) => { error!("Failed to get hardware info with {:?}", e); None } }; + let res = client::post(url) .header("User-Agent", "Actix-web") .json(OperatorCheckinMessage { @@ -198,8 +210,9 @@ fn checkin() { .json() .from_err() .and_then(move |new_settings: OperatorUpdateMessage| { + let mut network = rita_client.network; trace!("Updating from operator settings"); - let mut payment = SETTING.get_payment_mut(); + let mut payment = rita_client.payment; if use_operator_price { // This will be true on devices that have integrated switches @@ -225,13 +238,13 @@ fn checkin() { if let Some(new_chain) = new_settings.withdraw_chain { payment.withdraw_chain = new_chain; } - drop(payment); + rita_client.payment = payment; trace!("Done with payment"); - let mut operator = SETTING.get_operator_mut(); + let mut operator = rita_client.operator; let new_operator_fee = Uint256::from(new_settings.operator_fee); operator.operator_fee = new_operator_fee; - drop(operator); + rita_client.operator = operator; merge_settings_safely(new_settings.merge_json); @@ -245,14 +258,13 @@ fn checkin() { if new_settings.firmware_feed.is_some() && !user_set_release_feed { handle_release_feed_update(new_settings.firmware_feed); } - match new_settings.operator_action { Some(OperatorAction::ResetShaper) => flag_reset_shaper(), Some(OperatorAction::Reboot) => { let _res = KI.run_command("reboot", &[]); } Some(OperatorAction::ResetRouterPassword) => { - SETTING.get_network_mut().rita_dashboard_password = None; + network.rita_dashboard_password = None; } Some(OperatorAction::ResetWiFiPassword) => { let _res = reset_wifi_pass(); @@ -264,13 +276,13 @@ fn checkin() { let _res = KI.run_command("ash", &["/etc/update.ash"]); } Some(OperatorAction::ChangeOperatorAddress { new_address }) => { - SETTING.get_operator_mut().operator_address = new_address; + rita_client.operator.operator_address = new_address; } Some(OperatorAction::ChangeReleaseFeedAndUpdate { feed }) => { handle_release_feed_update(Some(feed)); // this is the escape hatch for the user setting their own release feed. Once an operator manually // updates them they are back in the 'normal' group - let mut network = SETTING.get_network_mut(); + network.user_set_release_feed = false; // this runs the update shell script, if an update is found a reboot will occur // it is possible that the script fails to grab the package index or a package @@ -281,10 +293,11 @@ fn checkin() { None => {} } - let mut network = SETTING.get_network_mut(); network.shaper_settings = new_settings.shaper_settings; - drop(network); + rita_client.network = network; + let copy = rita_client; + settings::set_rita_client(copy); trace!("Successfully completed OperatorUpdate"); Ok(()) }) @@ -326,7 +339,7 @@ fn merge_settings_safely(new_settings: Value) { if let Value::Object(map) = new_settings.clone() { let contains_forbidden_key = contains_forbidden_key(map, &FORBIDDEN_MERGE_VALUES); if !contains_forbidden_key { - match SETTING.merge(new_settings.clone()) { + match settings::get_rita_client().merge(new_settings.clone()) { Ok(_) => trace!("Merged new settings successfully {:?}", new_settings), Err(e) => error!( "Failed to merge OperatorUpdate settings {:?} {:?}", @@ -368,6 +381,8 @@ fn contains_forbidden_key(map: Map, forbidden_values: &[&str]) -> #[cfg(test)] mod tests { + use serde_json::json; + use super::*; const FORBIDDEN_MERGE_VALUES: [&str; 2] = ["test_key", "other_test_key"]; diff --git a/rita/src/rita_client/rita_loop/mod.rs b/rita_client/src/rita_loop/mod.rs similarity index 83% rename from rita/src/rita_client/rita_loop/mod.rs rename to rita_client/src/rita_loop/mod.rs index 7f6f032f9..9ce1566e4 100644 --- a/rita/src/rita_client/rita_loop/mod.rs +++ b/rita_client/src/rita_loop/mod.rs @@ -4,20 +4,20 @@ //! This loop manages exit signup based on the settings configuration state and deploys an exit vpn //! tunnel if the signup was successful on the selected exit. -use crate::rita_client::exit_manager::ExitManager; -use crate::rita_client::heartbeat::send_udp_heartbeat; -use crate::rita_client::light_client_manager::light_client_hello_response; -use crate::rita_client::light_client_manager::LightClientManager; -use crate::rita_client::light_client_manager::Watch; -use crate::rita_client::operator_fee_manager::OperatorFeeManager; -use crate::rita_client::operator_fee_manager::Tick as OperatorTick; -use crate::rita_client::operator_update::{OperatorUpdate, Update}; -use crate::rita_client::traffic_watcher::GetExitDestPrice; -use crate::rita_client::traffic_watcher::TrafficWatcher; -use crate::rita_common::tunnel_manager::GetNeighbors; -use crate::rita_common::tunnel_manager::GetTunnels; -use crate::rita_common::tunnel_manager::TunnelManager; -use crate::SETTING; +use crate::exit_manager::ExitManager; +use crate::heartbeat::send_udp_heartbeat; +use crate::light_client_manager::light_client_hello_response; +use crate::light_client_manager::LightClientManager; +use crate::light_client_manager::Watch; +use crate::operator_fee_manager::OperatorFeeManager; +use crate::operator_fee_manager::Tick as OperatorTick; +use crate::operator_update::{OperatorUpdate, Update}; +use crate::traffic_watcher::GetExitDestPrice; +use crate::traffic_watcher::TrafficWatcher; +use rita_common::tunnel_manager::GetNeighbors; +use rita_common::tunnel_manager::GetTunnels; +use rita_common::tunnel_manager::TunnelManager; + use actix::{ Actor, ActorContext, Addr, Arbiter, AsyncContext, Context, Handler, Message, Supervised, SystemService, @@ -27,8 +27,6 @@ use actix_web::{server, App}; use althea_types::ExitState; use failure::Error; use futures01::future::Future; -use settings::client::RitaClientSettings; -use settings::RitaCommonSettings; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; @@ -54,7 +52,11 @@ pub fn set_gateway_client(input: bool) { /// and needs info to assist them. The logging setting may be inspected to disable metrics /// not required for a normal operator pub fn metrics_permitted() -> bool { - SETTING.get_log().enabled || SETTING.get_operator().operator_address.is_some() + settings::get_rita_client().log.enabled + || settings::get_rita_client() + .operator + .operator_address + .is_some() } pub struct RitaLoop {} @@ -154,8 +156,8 @@ impl Handler for RitaLoop { } pub fn check_rita_client_actors() { - assert!(crate::rita_client::rita_loop::RitaLoop::from_registry().connected()); - assert!(crate::rita_client::exit_manager::ExitManager::from_registry().connected()); + assert!(crate::rita_loop::RitaLoop::from_registry().connected()); + assert!(crate::exit_manager::ExitManager::from_registry().connected()); } /// There is a complicated corner case where the gateway is a client and a relay to @@ -171,7 +173,12 @@ fn check_for_gateway_client_billing_corner_case() -> impl Future impl Future for TrafficWatcher { // actix client behaves badly if you build a request the default way but don't give it // a domain name, so in order to do peer to peer requests we use with_connection and our own // socket specification - let our_id = SETTING.get_identity(); + let our_id = settings::get_rita_client().get_identity(); let request = format!("http://{}:{}/client_debt", exit_addr, exit_port); // it's an ipaddr appended to a u16, there's no real way for this to fail // unless of course it's an ipv6 address and you don't do the [] @@ -241,7 +240,7 @@ fn find_exit_route_capped( exit_mesh_ip: IpAddr, routes: Vec, ) -> Result { - let max_fee = SETTING.get_payment().max_fee; + let max_fee = settings::get_rita_client().payment.max_fee; let mut exit_route = get_installed_route(&exit_mesh_ip, &routes)?; if exit_route.price > max_fee { let mut capped_route = exit_route.clone(); diff --git a/rita_common/Cargo.toml b/rita_common/Cargo.toml new file mode 100644 index 000000000..c62af107e --- /dev/null +++ b/rita_common/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "rita_common" +version = "0.18.0" +edition = "2018" +license = "Apache-2.0" + +[dependencies] +actix = "0.7" +rand = "0.8.0" +ipnetwork = "0.14" +serde_derive = "1.0" +hex-literal = "0.3" +docopt = "1.1" +serde = "1.0" +bytes = "1.0" +byteorder = { version = "1.4", features = ["i128"] } +arrayvec = {version= "0.7", features = ["serde"]} +babel_monitor = { path = "../babel_monitor" } +flate2 = { version = "1.0", features = ["rust_backend"], default-features = false } +antenna_forwarding_client = {path = "../antenna_forwarding_client"} +actix-async = {package="actix", version = "0.11"} +auto-bridge = {path = "../auto_bridge"} +serde_json = "1.0" +log = { version = "0.4", features = ["release_max_level_info"] } +settings = { path = "../settings" } +clarity = "0.4" +futures = { version = "0.3", features = ["compat"] } +num256 = "0.3" +web30 = {git = "https://github.com/althea-net/web30", rev = "a600b8b8ebf2c49badee6b65ac90a56bbdad4ab9"} +num-traits="0.2" +failure = "0.1" +futures01 = { package = "futures", version = "0.1"} +tokio = "0.1" + +lazy_static = "1.4" + +althea_kernel_interface = { path = "../althea_kernel_interface" } + +actix-web-httpauth = {git = "https://github.com/althea-net/actix-web-httpauth"} +actix-web = { version = "0.7", default_features = false, features= ["ssl"] } + +async-web30 = {package="web30", version = "0.14"} + +althea_types = { path = "../althea_types" } +babel_monitor_legacy = {path = "../babel_monitor_legacy"} \ No newline at end of file diff --git a/rita/src/rita_common/blockchain_oracle/mod.rs b/rita_common/src/blockchain_oracle/mod.rs similarity index 95% rename from rita/src/rita_common/blockchain_oracle/mod.rs rename to rita_common/src/blockchain_oracle/mod.rs index 8eb2e4365..386f35622 100644 --- a/rita/src/rita_common/blockchain_oracle/mod.rs +++ b/rita_common/src/blockchain_oracle/mod.rs @@ -3,9 +3,8 @@ //! balance and nonce as well as computing more complicated things like the closing and //! payment threshold based on gas prices. -use crate::rita_common::rita_loop::fast_loop::FAST_LOOP_TIMEOUT; -use crate::rita_common::rita_loop::get_web3_server; -use crate::SETTING; +use crate::rita_loop::fast_loop::FAST_LOOP_TIMEOUT; +use crate::rita_loop::get_web3_server; use async_web30::client::Web3; use clarity::Address; use futures::future::join4; @@ -13,7 +12,7 @@ use num256::Int256; use num256::Uint256; use num_traits::identities::Zero; use settings::payment::PaymentSettings; -use settings::RitaCommonSettings; + use std::sync::Arc; use std::sync::RwLock; use std::time::Duration; @@ -59,7 +58,7 @@ pub fn zero_window_start() { pub const ORACLE_TIMEOUT: Duration = FAST_LOOP_TIMEOUT; pub async fn update() { - let payment_settings = SETTING.get_payment(); + let payment_settings = settings::get_rita_common().get_payment(); let our_address = payment_settings.eth_address.expect("No address!"); drop(payment_settings); @@ -82,7 +81,7 @@ async fn update_blockchain_info( let gas_price = web3.eth_gas_price(); let (balance, nonce, net_version, gas_price) = join4(balance, nonce, net_version, gas_price).await; - let mut payment_settings = SETTING.get_payment_mut(); + let mut payment_settings = settings::get_rita_common().get_payment(); match balance { Ok(balance) => update_balance( &full_node, @@ -106,6 +105,9 @@ async fn update_blockchain_info( Ok(nonce) => update_nonce(&full_node, nonce, &mut payment_settings.nonce), Err(e) => warn!("Failed to update nonce with {:?}", e), } + let mut common = settings::get_rita_common(); + common.set_payment(payment_settings); + settings::set_rita_common(common); } /// Gets the balance for the provided eth address and updates it @@ -234,9 +236,9 @@ fn update_gas_price( /// A very simple function placed here for convinence that indicates /// if the system should go into low balance mode pub fn low_balance() -> bool { - let payment_settings = SETTING.get_payment(); + let payment_settings = settings::get_rita_common().get_payment(); let balance = payment_settings.balance.clone(); - let balance_warning_level = payment_settings.balance_warning_level.clone(); + let balance_warning_level = payment_settings.balance_warning_level; balance < balance_warning_level } diff --git a/rita/src/rita_common/dashboard/babel.rs b/rita_common/src/dashboard/babel.rs similarity index 71% rename from rita/src/rita_common/dashboard/babel.rs rename to rita_common/src/dashboard/babel.rs index fef76fe89..9ee7d30b4 100644 --- a/rita/src/rita_common/dashboard/babel.rs +++ b/rita_common/src/dashboard/babel.rs @@ -1,14 +1,6 @@ -use crate::ARGS; -use crate::SETTING; -use ::actix_web::http::StatusCode; -use ::actix_web::Path; -use ::actix_web::{HttpRequest, HttpResponse, Result}; -use ::settings::FileWrite; -use ::settings::RitaCommonSettings; -// use babel_monitor::open_babel_stream; -// use babel_monitor::set_local_fee as babel_set_local_fee; -// use babel_monitor::set_metric_factor as babel_set_metric_factor; -// use babel_monitor::start_connection; +use actix_web::http::StatusCode; +use actix_web::Path; +use actix_web::{HttpRequest, HttpResponse, Result}; use babel_monitor_legacy::open_babel_stream_legacy; use babel_monitor_legacy::set_local_fee_legacy as babel_set_local_fee_legacy; use babel_monitor_legacy::set_metric_factor_legacy as babel_set_metric_factor_legacy; @@ -20,7 +12,10 @@ use std::collections::HashMap; pub fn get_local_fee(_req: HttpRequest) -> Result { debug!("/local_fee GET hit"); let mut ret = HashMap::new(); - ret.insert("local_fee", SETTING.get_payment().local_fee); + ret.insert( + "local_fee", + settings::get_rita_common().get_payment().local_fee, + ); Ok(HttpResponse::Ok().json(ret)) } @@ -28,7 +23,10 @@ pub fn get_local_fee(_req: HttpRequest) -> Result { pub fn get_metric_factor(_req: HttpRequest) -> Result { debug!("/local_fee GET hit"); let mut ret = HashMap::new(); - ret.insert("metric_factor", SETTING.get_network().metric_factor); + ret.insert( + "metric_factor", + settings::get_rita_common().get_network().metric_factor, + ); Ok(HttpResponse::Ok().json(ret)) } @@ -36,8 +34,8 @@ pub fn get_metric_factor(_req: HttpRequest) -> Result { pub fn set_local_fee(path: Path) -> Box> { let new_fee = path.into_inner(); debug!("/local_fee/{} POST hit", new_fee); - let babel_port = SETTING.get_network().babel_port; - let max_fee = SETTING.get_payment().max_fee; + let babel_port = settings::get_rita_common().get_network().babel_port; + let max_fee = settings::get_rita_common().get_payment().max_fee; // prevent the user from setting a higher price than they would pay // themselves let new_fee = if new_fee > max_fee { max_fee } else { new_fee }; @@ -53,13 +51,16 @@ pub fn set_local_fee(path: Path) -> Box) -> Box) -> Box> { let new_factor = path.into_inner(); debug!("/metric_factor/{} POST hit", new_factor); - let babel_port = SETTING.get_network().babel_port; + let babel_port = settings::get_rita_common().get_network().babel_port; Box::new(open_babel_stream_legacy(babel_port).then(move |stream| { // if we can't get to babel here we panic @@ -85,10 +86,14 @@ pub fn set_metric_factor(path: Path) -> Box Result { - let nick = SETTING.get_network().nickname; + let nick = settings::get_rita_common().get_network().nickname; if let Some(nick) = nick { Ok(HttpResponse::Ok().json(nick.to_string())) @@ -25,12 +22,17 @@ pub fn set_nickname(nickname: Json) -> Result { let new_nick = &nickname.nickname; match ArrayString::<32>::from(new_nick) { Ok(new) => { - SETTING.get_network_mut().nickname = Some(new); + let mut common = settings::get_rita_common(); + let mut network = settings::get_rita_common().get_network(); + network.nickname = Some(new); + common.set_network(network); + settings::set_rita_common(common); // try and save the config and fail if we can't - if let Err(e) = SETTING.write().unwrap().write(&ARGS.flag_config) { + if let Err(e) = settings::write_config() { return Err(e); } + Ok(HttpResponse::Ok().json(())) } Err(_e) => bail!("Insufficient capacity for string!"), @@ -40,17 +42,20 @@ pub fn set_nickname(nickname: Json) -> Result { /// sets a nickname if there is not one already set #[allow(dead_code)] pub fn maybe_set_nickname(new_nick: String) -> Result<(), Error> { - let mut network = SETTING.get_network_mut(); + let mut common = settings::get_rita_common(); + let mut network = settings::get_rita_common().get_network(); + if network.nickname.is_none() && (new_nick != "AltheaHome-2.4" || new_nick != "AltheaHome-5") { match ArrayString::<32>::from(&new_nick) { Ok(new) => { network.nickname = Some(new); - drop(network); - + common.set_network(network); + settings::set_rita_common(common); // try and save the config and fail if we can't - if let Err(e) = SETTING.write().unwrap().write(&ARGS.flag_config) { + if let Err(e) = settings::write_config() { return Err(e); } + Ok(()) } Err(_e) => bail!("Insufficient capacity for string!"), diff --git a/rita/src/rita_common/dashboard/own_info.rs b/rita_common/src/dashboard/own_info.rs similarity index 83% rename from rita/src/rita_common/dashboard/own_info.rs rename to rita_common/src/dashboard/own_info.rs index 19fc15956..bc549847a 100644 --- a/rita/src/rita_common/dashboard/own_info.rs +++ b/rita_common/src/dashboard/own_info.rs @@ -1,11 +1,9 @@ -use crate::rita_common::blockchain_oracle::low_balance; -use crate::rita_common::rita_loop::is_gateway; -use crate::SETTING; +use crate::blockchain_oracle::low_balance; +use crate::rita_loop::is_gateway; use actix_web::{HttpRequest, Json}; use clarity::Address; use failure::Error; use num256::{Int256, Uint256}; -use settings::RitaCommonSettings; pub static READABLE_VERSION: &str = "Beta 18 RC0"; @@ -27,7 +25,7 @@ pub struct OwnInfo { pub fn get_own_info(_req: HttpRequest) -> Result, Error> { debug!("Get own info endpoint hit!"); - let payment_settings = SETTING.get_payment(); + let payment_settings = settings::get_rita_common().get_payment(); let eth_address = payment_settings.eth_address.unwrap(); let balance = payment_settings.balance.clone(); let pay_threshold = payment_settings.pay_threshold.clone(); @@ -35,9 +33,9 @@ pub fn get_own_info(_req: HttpRequest) -> Result, Error> { let local_fee = payment_settings.local_fee; let client_can_use_free_tier = payment_settings.client_can_use_free_tier; - let network_settings = SETTING.get_network(); + let network_settings = settings::get_rita_common().get_network(); let metric_factor = network_settings.metric_factor; - let device = network_settings.device.clone(); + let device = network_settings.device; let is_gateway = is_gateway(); let reply = OwnInfo { diff --git a/rita/src/rita_common/dashboard/settings.rs b/rita_common/src/dashboard/settings.rs similarity index 60% rename from rita/src/rita_common/dashboard/settings.rs rename to rita_common/src/dashboard/settings.rs index 90781311c..65d6a87eb 100644 --- a/rita/src/rita_common/dashboard/settings.rs +++ b/rita_common/src/dashboard/settings.rs @@ -1,19 +1,17 @@ -use crate::rita_common::network_endpoints::JsonStatusResponse; -use crate::SETTING; -use ::actix_web::{HttpRequest, Json, Result}; -use ::settings::RitaCommonSettings; +use crate::network_endpoints::JsonStatusResponse; +use actix_web::{HttpRequest, Json, Result}; use failure::Error; pub fn get_settings(_req: HttpRequest) -> Result, Error> { debug!("Get settings endpoint hit!"); - Ok(Json(SETTING.get_all()?)) + Ok(Json(settings::get_config_json()?)) } pub fn set_settings( new_settings: Json, ) -> Result, Error> { debug!("Set settings endpoint hit!"); - SETTING.merge(new_settings.into_inner())?; + settings::merge_config_json(new_settings.into_inner())?; JsonStatusResponse::new(Ok("New settings applied".to_string())) } diff --git a/rita/src/rita_common/dashboard/token_bridge.rs b/rita_common/src/dashboard/token_bridge.rs similarity index 58% rename from rita/src/rita_common/dashboard/token_bridge.rs rename to rita_common/src/dashboard/token_bridge.rs index 8e1795e8a..0a1a2dcf0 100644 --- a/rita/src/rita_common/dashboard/token_bridge.rs +++ b/rita_common/src/dashboard/token_bridge.rs @@ -1,5 +1,5 @@ -use crate::rita_common::token_bridge::get_bridge_status as get_status; -use crate::rita_common::token_bridge::BridgeStatus; +use crate::token_bridge::get_bridge_status as get_status; +use crate::token_bridge::BridgeStatus; use ::actix_web::{HttpRequest, Json}; pub fn get_bridge_status(_req: HttpRequest) -> Json { diff --git a/rita/src/rita_common/dashboard/usage.rs b/rita_common/src/dashboard/usage.rs similarity index 57% rename from rita/src/rita_common/dashboard/usage.rs rename to rita_common/src/dashboard/usage.rs index c2fbafdf5..77f9bd04c 100644 --- a/rita/src/rita_common/dashboard/usage.rs +++ b/rita_common/src/dashboard/usage.rs @@ -1,6 +1,6 @@ -use crate::rita_common::usage_tracker::handle_get_payments_data; -use crate::rita_common::usage_tracker::GetPayments; -use crate::rita_common::usage_tracker::PaymentHour; +use crate::usage_tracker::handle_get_payments_data; +use crate::usage_tracker::GetPayments; +use crate::usage_tracker::PaymentHour; use ::actix_web::{HttpRequest, Json}; use std::collections::VecDeque; diff --git a/rita/src/rita_common/dashboard/wallet.rs b/rita_common/src/dashboard/wallet.rs similarity index 89% rename from rita/src/rita_common/dashboard/wallet.rs rename to rita_common/src/dashboard/wallet.rs index d630ebb6a..a03531358 100644 --- a/rita/src/rita_common/dashboard/wallet.rs +++ b/rita_common/src/dashboard/wallet.rs @@ -1,8 +1,7 @@ -use crate::rita_common::blockchain_oracle::zero_window_start; -use crate::rita_common::rita_loop::get_web3_server; -use crate::rita_common::token_bridge::withdraw as bridge_withdraw; -use crate::rita_common::token_bridge::Withdraw as WithdrawMsg; -use crate::SETTING; +use crate::blockchain_oracle::zero_window_start; +use crate::rita_loop::get_web3_server; +use crate::token_bridge::withdraw as bridge_withdraw; +use crate::token_bridge::Withdraw as WithdrawMsg; use actix_web::http::StatusCode; use actix_web::HttpResponse; use actix_web::Path; @@ -11,7 +10,7 @@ use clarity::{Address, Transaction}; use failure::Error; use futures01::{future, Future}; use num256::Uint256; -use settings::RitaCommonSettings; + use std::boxed::Box; use std::time::Duration; use web30::client::Web3; @@ -23,12 +22,11 @@ fn withdraw_handler( amount: Option, ) -> Box> { debug!("/withdraw/{:#x}/{:?} hit", address, amount); - let payment_settings = SETTING.get_payment(); + let payment_settings = settings::get_rita_common().get_payment(); let system_chain = payment_settings.system_chain; let withdraw_chain = payment_settings.withdraw_chain; let mut gas_price = payment_settings.gas_price.clone(); - let balance = payment_settings.balance.clone(); - drop(payment_settings); + let balance = payment_settings.balance; let mut withdraw_all = false; // if no amount is specified we are withdrawing our entire balance @@ -92,7 +90,7 @@ fn eth_compatable_withdraw( ) -> Box> { let full_node = get_web3_server(); let web3 = Web3::new(&full_node, WITHDRAW_TIMEOUT); - let payment_settings = SETTING.get_payment(); + let payment_settings = settings::get_rita_common().get_payment(); if payment_settings.eth_address.is_none() { return Box::new(future::ok( HttpResponse::new(StatusCode::from_u16(504u16).unwrap()) @@ -132,7 +130,12 @@ fn eth_compatable_withdraw( Box::new(transaction_status.then(move |result| match result { Ok(tx_id) => Box::new(future::ok({ - SETTING.get_payment_mut().nonce += 1u64.into(); + let mut common = settings::get_rita_common(); + let mut payment = settings::get_rita_common().get_payment(); + + payment.nonce += 1u64.into(); + common.set_payment(payment); + settings::set_rita_common(common); HttpResponse::Ok().json(format!("txid:{:#066x}", tx_id)) })), Err(e) => { diff --git a/rita/src/rita_common/dashboard/wg_key.rs b/rita_common/src/dashboard/wg_key.rs similarity index 73% rename from rita/src/rita_common/dashboard/wg_key.rs rename to rita_common/src/dashboard/wg_key.rs index 4adf34942..3abbeada2 100644 --- a/rita/src/rita_common/dashboard/wg_key.rs +++ b/rita_common/src/dashboard/wg_key.rs @@ -1,10 +1,8 @@ -use crate::SETTING; use actix_web::{HttpRequest, HttpResponse, Result}; use failure::Error; -use settings::RitaCommonSettings; pub fn get_wg_public_key(_req: HttpRequest) -> Result { - let wg_public_key = SETTING.get_network().wg_public_key; + let wg_public_key = settings::get_rita_common().get_network().wg_public_key; if let Some(wg_public_key) = wg_public_key { Ok(HttpResponse::Ok().json(wg_public_key.to_string())) diff --git a/rita/src/rita_common/debt_keeper/mod.rs b/rita_common/src/debt_keeper/mod.rs similarity index 84% rename from rita/src/rita_common/debt_keeper/mod.rs rename to rita_common/src/debt_keeper/mod.rs index 363165542..a505564a2 100755 --- a/rita/src/rita_common/debt_keeper/mod.rs +++ b/rita_common/src/debt_keeper/mod.rs @@ -8,16 +8,14 @@ //! increase the amount we owe Bob? That's probably a vulnerability rabbit hole at the very least. //! Hence we need an incoming payments parameter to take money out of. This of course implies half //! of the excess complexity you see, managing an incoming payments pool versus a incoming debts pool +use crate::payment_controller::{self, PaymentController}; +use crate::payment_validator::PAYMENT_SEND_TIMEOUT; +use crate::simulated_txfee_manager::add_tx_to_total; +use crate::tunnel_manager::TunnelAction; +use crate::tunnel_manager::TunnelChange; +use crate::tunnel_manager::TunnelManager; +use crate::tunnel_manager::TunnelStateChange; -use crate::rita_common::payment_controller; -use crate::rita_common::payment_controller::PaymentController; -use crate::rita_common::payment_validator::PAYMENT_SEND_TIMEOUT; -use crate::rita_common::simulated_txfee_manager::add_tx_to_total; -use crate::rita_common::tunnel_manager::TunnelAction; -use crate::rita_common::tunnel_manager::TunnelChange; -use crate::rita_common::tunnel_manager::TunnelManager; -use crate::rita_common::tunnel_manager::TunnelStateChange; -use crate::SETTING; use actix::SystemService; use althea_types::{Identity, PaymentTx}; use failure::Error; @@ -25,7 +23,7 @@ use num256::{Int256, Uint256}; use num_traits::identities::Zero; use num_traits::Signed; use serde_json::Error as SerdeError; -use settings::RitaCommonSettings; + use std::collections::HashMap; use std::fs::File; use std::io::Error as IOError; @@ -73,6 +71,20 @@ pub struct NodeDebtData { pub last_successful_payment: Option, } +impl Default for NodeDebtData { + fn default() -> Self { + NodeDebtData { + total_payment_received: Uint256::from(0u32), + total_payment_sent: Uint256::from(0u32), + debt: Int256::from(0), + incoming_payments: Uint256::from(0u32), + action: DebtAction::OpenTunnel, + payment_in_flight: false, + payment_in_flight_start: None, + last_successful_payment: None, + } + } +} impl NodeDebtData { pub fn new() -> NodeDebtData { NodeDebtData { @@ -114,7 +126,7 @@ fn ser_to_debt_data(input: DebtDataSer) -> DebtData { // discard the entry, in the case that they do have some incoming payments the user // deserves to have that credit applied in the future so we must retain the entry and // reset the debt - if SETTING.get_payment().forgive_on_reboot { + if settings::get_rita_common().get_payment().forgive_on_reboot { if d.debt <= Int256::zero() && d.incoming_payments == Uint256::zero() { continue; } else if d.debt <= Int256::zero() { @@ -250,7 +262,7 @@ pub fn send_debt_update() -> Result<(), Error> { DebtAction::MakePayment { to, amount } => PaymentController::from_registry().do_send( payment_controller::MakePayment(PaymentTx { to, - from: match SETTING.get_identity() { + from: match settings::get_rita_common().get_identity() { Some(id) => id, None => bail!("Identity has no mesh IP ready yet"), }, @@ -271,9 +283,9 @@ pub fn send_debt_update() -> Result<(), Error> { impl Default for DebtKeeper { fn default() -> DebtKeeper { - assert!(SETTING.get_payment().pay_threshold >= Int256::zero()); - assert!(SETTING.get_payment().close_threshold <= Int256::zero()); - let file = File::open(SETTING.get_payment().debts_file.clone()); + assert!(settings::get_rita_common().get_payment().pay_threshold >= Int256::zero()); + assert!(settings::get_rita_common().get_payment().close_threshold <= Int256::zero()); + let file = File::open(settings::get_rita_common().get_payment().debts_file); // if the loading process goes wrong for any reason, we just start again let blank_debt_keeper = DebtKeeper { last_save: None, @@ -316,8 +328,8 @@ impl Default for DebtKeeper { impl DebtKeeper { #[cfg(test)] pub fn new() -> Self { - assert!(SETTING.get_payment().pay_threshold >= Int256::zero()); - assert!(SETTING.get_payment().close_threshold <= Int256::zero()); + assert!(settings::get_rita_common().get_payment().pay_threshold >= Int256::zero()); + assert!(settings::get_rita_common().get_payment().close_threshold <= Int256::zero()); DebtKeeper { last_save: None, @@ -349,7 +361,7 @@ impl DebtKeeper { fn save(&mut self) -> Result<(), IOError> { // convert to the serializeable format and dump to the disk let serialized = serde_json::to_string(&debt_data_to_ser(self.debt_data.clone()))?; - let mut file = File::create(SETTING.get_payment().debts_file.clone())?; + let mut file = File::create(settings::get_rita_common().get_payment().debts_file)?; file.write_all(serialized.as_bytes()) } @@ -483,7 +495,7 @@ impl DebtKeeper { ); } - let payment_settings = SETTING.get_payment(); + let payment_settings = settings::get_rita_common().get_payment(); let close_threshold = payment_settings.close_threshold.clone(); let pay_threshold = payment_settings.pay_threshold.clone(); let fudge_factor = payment_settings.fudge_factor; @@ -563,7 +575,9 @@ impl DebtKeeper { // routers where this unapplied credit is several dollars worth, so it's best to remit // that to the users by applying it here. let zero = Uint256::zero(); - if SETTING.get_payment().apply_incoming_credit_immediately + if settings::get_rita_common() + .get_payment() + .apply_incoming_credit_immediately && debt_data.incoming_payments > zero { debt_data.action = DebtAction::OpenTunnel; @@ -626,8 +640,10 @@ pub fn get_debts_list() -> Vec { #[cfg(test)] mod tests { - use super::*; use rand::Rng; + use settings::client::RitaClientSettings; + + use super::*; fn get_test_identity() -> Identity { Identity::new( @@ -663,8 +679,11 @@ mod tests { #[test] fn test_single_suspend() { - SETTING.get_payment_mut().pay_threshold = Int256::from(5); - SETTING.get_payment_mut().close_threshold = Int256::from(-10); + settings::set_rita_client(RitaClientSettings::default()); + let mut common = settings::get_rita_common(); + let mut payment = settings::get_rita_common().get_payment(); + payment.pay_threshold = Int256::from(5); + payment.close_threshold = Int256::from(-10); let mut d = DebtKeeper::new(); @@ -672,13 +691,22 @@ mod tests { d.traffic_update(&ident, Int256::from(-100i64)); + common.set_payment(payment); + settings::set_rita_common(common); + assert_eq!(d.send_update(&ident).unwrap(), DebtAction::SuspendTunnel); } #[test] fn test_single_overpay() { - SETTING.get_payment_mut().pay_threshold = Int256::from(5); - SETTING.get_payment_mut().close_threshold = Int256::from(-10); + settings::set_rita_client(RitaClientSettings::default()); + let mut common = settings::get_rita_common(); + let mut payment = settings::get_rita_common().get_payment(); + + payment.pay_threshold = Int256::from(5); + payment.close_threshold = Int256::from(-10); + common.set_payment(payment); + settings::set_rita_common(common); let mut d = DebtKeeper::new(); @@ -692,15 +720,22 @@ mod tests { #[test] fn test_single_pay() { - SETTING.get_payment_mut().pay_threshold = Int256::from(5); - SETTING.get_payment_mut().close_threshold = Int256::from(-10); - SETTING.get_payment_mut().debt_limit_enabled = false; + settings::set_rita_client(RitaClientSettings::default()); + let mut common = settings::get_rita_common(); + let mut payment = settings::get_rita_common().get_payment(); + + payment.pay_threshold = Int256::from(5); + payment.close_threshold = Int256::from(-10); + payment.debt_limit_enabled = false; let mut d = DebtKeeper::new(); let ident = get_test_identity(); d.traffic_update(&ident, Int256::from(100)); + common.set_payment(payment); + settings::set_rita_common(common); + assert_eq!( d.send_update(&ident).unwrap(), DebtAction::MakePayment { @@ -712,15 +747,22 @@ mod tests { #[test] fn test_single_pay_limited() { - SETTING.get_payment_mut().pay_threshold = Int256::from(5); - SETTING.get_payment_mut().close_threshold = Int256::from(-10); - SETTING.get_payment_mut().debt_limit_enabled = true; + settings::set_rita_client(RitaClientSettings::default()); + let mut payment = settings::get_rita_common().get_payment(); + + payment.pay_threshold = Int256::from(5); + payment.close_threshold = Int256::from(-10); + payment.debt_limit_enabled = true; let mut d = DebtKeeper::new(); let ident = get_test_identity(); d.traffic_update(&ident, Int256::from(100)); + let mut common = settings::get_rita_common(); + common.set_payment(payment); + settings::set_rita_common(common); + assert_eq!( d.send_update(&ident).unwrap(), DebtAction::MakePayment { @@ -732,8 +774,15 @@ mod tests { #[test] fn test_single_reopen() { - SETTING.get_payment_mut().pay_threshold = Int256::from(5); - SETTING.get_payment_mut().close_threshold = Int256::from(-10); + settings::set_rita_client(RitaClientSettings::default()); + + let mut payment = settings::get_rita_common().get_payment(); + + payment.pay_threshold = Int256::from(5); + payment.close_threshold = Int256::from(-10); + let mut common = settings::get_rita_common(); + common.set_payment(payment); + settings::set_rita_common(common); let mut d = DebtKeeper::new(); let ident = get_test_identity(); @@ -749,9 +798,12 @@ mod tests { #[test] fn test_multi_pay() { - SETTING.get_payment_mut().pay_threshold = Int256::from(5); - SETTING.get_payment_mut().close_threshold = Int256::from(-10); - SETTING.get_payment_mut().debt_limit_enabled = false; + settings::set_rita_client(RitaClientSettings::default()); + let mut payment = settings::get_rita_common().get_payment(); + + payment.pay_threshold = Int256::from(5); + payment.close_threshold = Int256::from(-10); + payment.debt_limit_enabled = false; let mut d = DebtKeeper::new(); let ident = get_test_identity(); @@ -760,6 +812,10 @@ mod tests { d.traffic_update(&ident, Int256::from(100)) } + let mut common = settings::get_rita_common(); + common.set_payment(payment); + settings::set_rita_common(common); + assert_eq!( d.send_update(&ident).unwrap(), DebtAction::MakePayment { @@ -771,9 +827,12 @@ mod tests { #[test] fn test_multi_pay_lmited() { - SETTING.get_payment_mut().pay_threshold = Int256::from(5); - SETTING.get_payment_mut().close_threshold = Int256::from(-10); - SETTING.get_payment_mut().debt_limit_enabled = true; + settings::set_rita_client(RitaClientSettings::default()); + let mut payment = settings::get_rita_common().get_payment(); + + payment.pay_threshold = Int256::from(5); + payment.close_threshold = Int256::from(-10); + payment.debt_limit_enabled = true; let mut d = DebtKeeper::new(); let ident = get_test_identity(); @@ -782,6 +841,10 @@ mod tests { d.traffic_update(&ident, Int256::from(100)) } + let mut common = settings::get_rita_common(); + common.set_payment(payment); + settings::set_rita_common(common); + assert_eq!( d.send_update(&ident).unwrap(), DebtAction::MakePayment { @@ -793,14 +856,21 @@ mod tests { #[test] fn test_multi_fail() { - SETTING.get_payment_mut().pay_threshold = Int256::from(5); - SETTING.get_payment_mut().close_threshold = Int256::from(-10); + settings::set_rita_client(RitaClientSettings::default()); + let mut payment = settings::get_rita_common().get_payment(); + + payment.pay_threshold = Int256::from(5); + payment.close_threshold = Int256::from(-10); let mut d = DebtKeeper::new(); let ident = get_test_identity(); d.traffic_update(&ident, Int256::from(-10100i64)); + let mut common = settings::get_rita_common(); + common.set_payment(payment); + settings::set_rita_common(common); + // send lots of payments for _ in 0..100 { d.payment_received(&ident, Uint256::from(100u64)).unwrap(); @@ -811,8 +881,11 @@ mod tests { #[test] fn test_multi_reopen() { - SETTING.get_payment_mut().pay_threshold = Int256::from(5); - SETTING.get_payment_mut().close_threshold = Int256::from(-10); + settings::set_rita_client(RitaClientSettings::default()); + let mut payment = settings::get_rita_common().get_payment(); + + payment.pay_threshold = Int256::from(5); + payment.close_threshold = Int256::from(-10); let mut d = DebtKeeper::new(); let ident = get_test_identity(); @@ -823,6 +896,10 @@ mod tests { d.payment_received(&ident, Uint256::from(100u64)).unwrap(); } + let mut common = settings::get_rita_common(); + common.set_payment(payment); + settings::set_rita_common(common); + assert_eq!(d.send_update(&ident).unwrap(), DebtAction::SuspendTunnel); d.payment_received(&ident, Uint256::from(200u64)).unwrap(); @@ -832,9 +909,14 @@ mod tests { #[test] fn test_credit_reopen() { - SETTING.get_payment_mut().pay_threshold = Int256::from(5); - SETTING.get_payment_mut().close_threshold = Int256::from(-10); - SETTING.get_payment_mut().debt_limit_enabled = false; + settings::set_rita_client(RitaClientSettings::default()); + let mut payment = settings::get_rita_common().get_payment(); + payment.pay_threshold = Int256::from(5); + payment.close_threshold = Int256::from(-10); + payment.debt_limit_enabled = false; + let mut common = settings::get_rita_common(); + common.set_payment(payment); + settings::set_rita_common(common); let mut d = DebtKeeper::new(); let ident = get_test_identity(); @@ -858,13 +940,19 @@ mod tests { #[test] fn test_credit_reopen_limited() { - SETTING.get_payment_mut().pay_threshold = Int256::from(10); - SETTING.get_payment_mut().close_threshold = Int256::from(-100); - SETTING.get_payment_mut().debt_limit_enabled = true; + let mut payment = settings::get_rita_common().get_payment(); + + payment.pay_threshold = Int256::from(10); + payment.close_threshold = Int256::from(-100); + payment.debt_limit_enabled = true; let mut d = DebtKeeper::new(); let ident = get_test_identity(); + let mut common = settings::get_rita_common(); + common.set_payment(payment); + settings::set_rita_common(common); + // when the debt limit is enabled these tests have to get a little more real // the values stop making sense once you eceed the close_threshold because that's // the desired behavior of a system with the debt limit on, so you can't add in @@ -887,13 +975,20 @@ mod tests { #[test] fn test_payment_fail() { - SETTING.get_payment_mut().pay_threshold = Int256::from(5); - SETTING.get_payment_mut().close_threshold = Int256::from(-10); - SETTING.get_payment_mut().debt_limit_enabled = false; + settings::set_rita_client(RitaClientSettings::default()); + let mut common = settings::get_rita_common(); + let mut payment = settings::get_rita_common().get_payment(); + + payment.pay_threshold = Int256::from(5); + payment.close_threshold = Int256::from(-10); + payment.debt_limit_enabled = false; let mut d = DebtKeeper::new(); let ident = get_test_identity(); + common.set_payment(payment); + settings::set_rita_common(common); + // generate a bunch of traffic for _ in 0..100 { d.traffic_update(&ident, Int256::from(100)) @@ -963,9 +1058,17 @@ mod tests { #[test] fn test_payment_fail_limited() { - SETTING.get_payment_mut().pay_threshold = Int256::from(5); - SETTING.get_payment_mut().close_threshold = Int256::from(-10); - SETTING.get_payment_mut().debt_limit_enabled = true; + settings::set_rita_client(RitaClientSettings::default()); + + let mut common = settings::get_rita_common(); + let mut payment = common.get_payment(); + + payment.pay_threshold = Int256::from(5); + payment.close_threshold = Int256::from(-10); + payment.debt_limit_enabled = true; + + common.set_payment(payment); + settings::set_rita_common(common); // same as above except debt is limited, so we will be paying much // smaller amounts than we are setup to 'owe' @@ -1040,6 +1143,7 @@ mod tests { #[test] fn test_debts_saving() { + settings::set_rita_client(RitaClientSettings::default()); let mut test_they_owe = NodeDebtData::new(); test_they_owe.debt = Int256::from(-500_000i64); let they_owe = (get_random_test_identity(), test_they_owe); diff --git a/rita/src/rita_common/hello_handler/mod.rs b/rita_common/src/hello_handler/mod.rs similarity index 95% rename from rita/src/rita_common/hello_handler/mod.rs rename to rita_common/src/hello_handler/mod.rs index 87d479ebb..d3c1885c5 100644 --- a/rita/src/rita_common/hello_handler/mod.rs +++ b/rita_common/src/hello_handler/mod.rs @@ -5,9 +5,9 @@ //! peer listener gets udp ImHere -> TunnelManager tries to contact peer with hello //! -> hello manager actually manages that request -> hello manager calls back to tunnel manager -use crate::rita_common::peer_listener::Peer; -use crate::rita_common::tunnel_manager::id_callback::IdentityCallback; -use crate::rita_common::tunnel_manager::{PortCallback, TunnelManager}; +use crate::peer_listener::Peer; +use crate::tunnel_manager::id_callback::IdentityCallback; +use crate::tunnel_manager::{PortCallback, TunnelManager}; use actix::{Actor, Context, Handler, Message, ResponseFuture, Supervised, SystemService}; use actix_web::client::Connection; use actix_web::{client, HttpMessage, Result}; diff --git a/rita_common/src/lib.rs b/rita_common/src/lib.rs new file mode 100644 index 000000000..a0aab2a91 --- /dev/null +++ b/rita_common/src/lib.rs @@ -0,0 +1,57 @@ +#[macro_use] +extern crate log; + +#[macro_use] +extern crate lazy_static; + +#[macro_use] +extern crate failure; + +#[macro_use] +extern crate serde_derive; +extern crate arrayvec; + +use althea_kernel_interface::KernelInterface; + +use althea_kernel_interface::LinuxCommandRunner; + +lazy_static! { + pub static ref KI: Box = Box::new(LinuxCommandRunner {}); +} + +pub mod blockchain_oracle; +pub mod dashboard; +pub mod debt_keeper; +pub mod hello_handler; +pub mod network_endpoints; +pub mod network_monitor; +pub mod payment_controller; +pub mod payment_validator; +pub mod peer_listener; +pub mod rita_loop; +pub mod simulated_txfee_manager; +pub mod token_bridge; +pub mod traffic_watcher; +pub mod tunnel_manager; +pub mod usage_tracker; +pub mod utils; + +pub use crate::dashboard::babel::*; +pub use crate::dashboard::debts::*; +pub use crate::dashboard::development::*; +pub use crate::dashboard::nickname::*; +pub use crate::dashboard::own_info::*; +pub use crate::dashboard::settings::*; +pub use crate::dashboard::token_bridge::*; +pub use crate::dashboard::usage::*; +pub use crate::dashboard::wallet::*; +pub use crate::dashboard::wg_key::*; +pub use crate::peer_listener::message::*; +pub use crate::rita_loop::fast_loop::*; +pub use crate::rita_loop::slow_loop::*; +pub use crate::tunnel_manager::gc::*; +pub use crate::tunnel_manager::id_callback::*; +pub use crate::tunnel_manager::neighbor_status::*; +pub use crate::tunnel_manager::shaping::*; +pub use crate::utils::ip_increment::*; +pub use crate::utils::wait_timeout::*; diff --git a/rita/src/rita_common/network_endpoints/mod.rs b/rita_common/src/network_endpoints/mod.rs similarity index 90% rename from rita/src/rita_common/network_endpoints/mod.rs rename to rita_common/src/network_endpoints/mod.rs index 49a492350..56a027937 100644 --- a/rita/src/rita_common/network_endpoints/mod.rs +++ b/rita_common/src/network_endpoints/mod.rs @@ -1,17 +1,16 @@ //! Network endptoints for common Rita functionality (such as exchanging hello messages) -use crate::rita_common::payment_validator::{validate_later, ToValidate}; -use crate::rita_common::peer_listener::Peer; -use crate::rita_common::tunnel_manager::id_callback::IdentityCallback; -use crate::rita_common::tunnel_manager::TunnelManager; -use crate::SETTING; +use crate::payment_validator::{validate_later, ToValidate}; +use crate::peer_listener::Peer; +use crate::tunnel_manager::id_callback::IdentityCallback; +use crate::tunnel_manager::TunnelManager; + use actix::registry::SystemService; use actix_web::http::StatusCode; use actix_web::{AsyncResponder, HttpRequest, HttpResponse, Json, Result}; use althea_types::{LocalIdentity, PaymentTx}; use failure::Error; use futures01::{future, Future}; -use settings::RitaCommonSettings; use std::boxed::Box; use std::net::SocketAddr; use std::time::Instant; @@ -101,7 +100,7 @@ pub fn hello_response( }; Ok(Json(LocalIdentity { - global: match SETTING.get_identity() { + global: match settings::get_rita_common().get_identity() { Some(id) => id, None => return Err(format_err!("Identity has no mesh IP ready yet")), }, @@ -117,6 +116,6 @@ pub fn version(_req: HttpRequest) -> String { format!( "crate ver {}\ngit hash {}", env!("CARGO_PKG_VERSION"), - env!("GIT_HASH") + settings::get_git_hash(), ) } diff --git a/rita/src/rita_common/network_monitor/mod.rs b/rita_common/src/network_monitor/mod.rs similarity index 97% rename from rita/src/rita_common/network_monitor/mod.rs rename to rita_common/src/network_monitor/mod.rs index 099118f8d..e07832f00 100644 --- a/rita/src/rita_common/network_monitor/mod.rs +++ b/rita_common/src/network_monitor/mod.rs @@ -8,12 +8,12 @@ //! as a bird flying through the connection rather than actual bloat. The solution here would be to also collect stats //! on traffic over every interface and base our action off of spikes in throughput as well as spikes in latency. -use crate::rita_common::rita_loop::fast_loop::FAST_LOOP_SPEED; -use crate::rita_common::tunnel_manager::shaping::ShapeMany; -use crate::rita_common::tunnel_manager::shaping::ShapingAdjust; -use crate::rita_common::tunnel_manager::shaping::ShapingAdjustAction; -use crate::rita_common::tunnel_manager::Neighbor as RitaNeighbor; -use crate::rita_common::tunnel_manager::TunnelManager; +use crate::rita_loop::fast_loop::FAST_LOOP_SPEED; +use crate::tunnel_manager::shaping::ShapeMany; +use crate::tunnel_manager::shaping::ShapingAdjust; +use crate::tunnel_manager::shaping::ShapingAdjustAction; +use crate::tunnel_manager::Neighbor as RitaNeighbor; +use crate::tunnel_manager::TunnelManager; use actix::Actor; use actix::Context; use actix::Handler; diff --git a/rita/src/rita_common/payment_controller/mod.rs b/rita_common/src/payment_controller/mod.rs similarity index 93% rename from rita/src/rita_common/payment_controller/mod.rs rename to rita_common/src/payment_controller/mod.rs index 7381520ac..736c4e9d6 100644 --- a/rita/src/rita_common/payment_controller/mod.rs +++ b/rita_common/src/payment_controller/mod.rs @@ -3,20 +3,20 @@ //! until it is successfully in a block, see payment_validator, once the payment is on //! the blockchain it's up to the reciever to validate that it's correct -use crate::rita_common::debt_keeper::payment_failed; -use crate::rita_common::payment_validator::{validate_later, ToValidate}; -use crate::rita_common::rita_loop::get_web3_server; -use crate::SETTING; +use crate::debt_keeper::payment_failed; +use crate::payment_validator::{validate_later, ToValidate}; +use crate::rita_loop::get_web3_server; + use actix::prelude::{Actor, Arbiter, Context, Handler, Message, Supervised, SystemService}; use actix_web::client; use actix_web::client::Connection; use althea_types::PaymentTx; use clarity::Transaction; -use failure::Error; +use failure::{bail, Error}; use futures01::future::Either; use futures01::{future, Future}; use num256::Uint256; -use settings::RitaCommonSettings; + use std::net::SocketAddr; use std::time::Duration; use std::time::Instant; @@ -66,7 +66,7 @@ impl PaymentController { /// This is called by debt_keeper to make payments. It sends a /// PaymentTx to the `mesh_ip` in its `to` field. fn make_payment(mut pmt: PaymentTx) -> Result<(), Error> { - let payment_settings = SETTING.get_payment(); + let payment_settings = settings::get_rita_common().get_payment(); let balance = payment_settings.balance.clone(); let nonce = payment_settings.nonce.clone(); let gas_price = payment_settings.gas_price.clone(); @@ -86,7 +86,7 @@ fn make_payment(mut pmt: PaymentTx) -> Result<(), Error> { let contact_socket: SocketAddr = match format!( "[{}]:{}", pmt.to.mesh_ip, - SETTING.get_network().rita_contact_port + settings::get_rita_common().get_network().rita_contact_port ) .parse() { @@ -168,7 +168,13 @@ fn make_payment(mut pmt: PaymentTx) -> Result<(), Error> { attempt: 0u8, })); } - {SETTING.get_payment_mut().nonce += 1u64.into();} + { + let mut common = settings::get_rita_common(); + let mut payment = common.get_payment(); + payment.nonce += 1u64.into(); + common.set_payment( payment); + settings::set_rita_common(common); + } let ts = ToValidate { diff --git a/rita/src/rita_common/payment_validator/mod.rs b/rita_common/src/payment_validator/mod.rs similarity index 97% rename from rita/src/rita_common/payment_validator/mod.rs rename to rita_common/src/payment_validator/mod.rs index a6d90eadb..28f3282ac 100644 --- a/rita/src/rita_common/payment_validator/mod.rs +++ b/rita_common/src/payment_validator/mod.rs @@ -7,18 +7,18 @@ //! off to debt keeper to be removed from the owed balance. Payments may time out after a //! configured period. -use crate::rita_common::debt_keeper::payment_received; -use crate::rita_common::debt_keeper::payment_succeeded; -use crate::rita_common::rita_loop::fast_loop::FAST_LOOP_TIMEOUT; -use crate::rita_common::rita_loop::get_web3_server; -use crate::rita_common::usage_tracker::update_payments; -use crate::SETTING; +use crate::debt_keeper::payment_received; +use crate::debt_keeper::payment_succeeded; +use crate::rita_loop::fast_loop::FAST_LOOP_TIMEOUT; +use crate::rita_loop::get_web3_server; +use crate::usage_tracker::update_payments; + use actix::System; use althea_types::PaymentTx; use async_web30::client::Web3; use async_web30::types::TransactionResponse; use num256::Uint256; -use settings::RitaCommonSettings; + use std::collections::HashSet; use std::fmt; use std::sync::Arc; @@ -170,7 +170,12 @@ pub async fn validate() { // get our address BEFORE we grab the history lock and scope the call to make // sure that the borrow checker drops it and we don't hold both locks at once - let our_address = { SETTING.get_payment().eth_address.unwrap() }; + let our_address = { + settings::get_rita_common() + .get_payment() + .eth_address + .unwrap() + }; let mut history = HISTORY.write().unwrap(); @@ -277,7 +282,10 @@ fn handle_tx_messaging( let from_address = ts.payment.from.eth_address; let amount = ts.payment.amount.clone(); let pmt = ts.payment.clone(); - let our_address = SETTING.get_payment().eth_address.expect("No Address!"); + let our_address = settings::get_rita_common() + .get_payment() + .eth_address + .expect("No Address!"); let to = match transaction.to { Some(val) => val, None => { diff --git a/rita/src/rita_common/peer_listener/message.rs b/rita_common/src/peer_listener/message.rs similarity index 100% rename from rita/src/rita_common/peer_listener/message.rs rename to rita_common/src/peer_listener/message.rs diff --git a/rita/src/rita_common/peer_listener/mod.rs b/rita_common/src/peer_listener/mod.rs similarity index 93% rename from rita/src/rita_common/peer_listener/mod.rs rename to rita_common/src/peer_listener/mod.rs index 551829f02..4ea4b2ad6 100644 --- a/rita/src/rita_common/peer_listener/mod.rs +++ b/rita_common/src/peer_listener/mod.rs @@ -6,14 +6,12 @@ //! rita_loop iteration we send out our own IP as a UDP broadcast packet and then get our peers //! off the queue. These are turned into Peer structs which are passed to TunnelManager to do //! whatever remaining work there may be. - -mod message; +pub mod message; use self::message::PeerMessage; use crate::KI; -use crate::SETTING; use failure::Error; -use settings::RitaCommonSettings; + use std::collections::HashMap; use std::net::{IpAddr, Ipv6Addr, SocketAddr, SocketAddrV6, UdpSocket}; use std::sync::Arc; @@ -38,7 +36,7 @@ pub struct Peer { impl Peer { pub fn new(ip: Ipv6Addr, idx: u32) -> Peer { - let port = SETTING.get_network().rita_hello_port; + let port = settings::get_rita_common().get_network().rita_hello_port; let socket = SocketAddrV6::new(ip, port, 0, idx); Peer { ifidx: idx, @@ -63,7 +61,7 @@ impl PeerListener { } fn listen_to_available_ifaces(peer_listener: &mut PeerListener) { - let interfaces = SETTING.get_network().peer_interfaces.clone(); + let interfaces = settings::get_rita_common().get_network().peer_interfaces; let iface_list = interfaces; for iface in iface_list.iter() { if !peer_listener.interfaces.contains_key(iface) { @@ -97,10 +95,13 @@ pub fn unlisten_interface(interface: String) { let mut writer = PEER_LISTENER.write().unwrap(); if writer.interfaces.contains_key(&ifname_to_delete) { writer.interfaces.remove(&ifname_to_delete); - SETTING - .get_network_mut() - .peer_interfaces - .remove(&ifname_to_delete); + let mut common = settings::get_rita_common(); + let mut network = common.get_network(); + + network.peer_interfaces.remove(&ifname_to_delete); + + common.set_network(network); + settings::set_rita_common(common); } else { error!("Tried to unlisten interface that's not present!") } @@ -122,8 +123,8 @@ pub struct ListenInterface { impl ListenInterface { pub fn new(ifname: &str) -> Result { - let port = SETTING.get_network().rita_hello_port; - let disc_ip = SETTING.get_network().discovery_ip; + let port = settings::get_rita_common().get_network().rita_hello_port; + let disc_ip = settings::get_rita_common().get_network().discovery_ip; debug!("Binding to {:?} for ListenInterface", ifname); // Lookup interface link local ip let link_ip = KI.get_link_local_device_ip(&ifname)?; diff --git a/rita/src/rita_common/rita_loop/fast_loop.rs b/rita_common/src/rita_loop/fast_loop.rs similarity index 91% rename from rita/src/rita_common/rita_loop/fast_loop.rs rename to rita_common/src/rita_loop/fast_loop.rs index 090ac7e4a..69df9ebda 100644 --- a/rita/src/rita_common/rita_loop/fast_loop.rs +++ b/rita_common/src/rita_loop/fast_loop.rs @@ -1,17 +1,16 @@ -use crate::rita_common::blockchain_oracle::update as BlockchainOracleUpdate; -use crate::rita_common::debt_keeper::send_debt_update; -use crate::rita_common::network_monitor::NetworkInfo as NetworkMonitorTick; -use crate::rita_common::network_monitor::NetworkMonitor; -use crate::rita_common::payment_validator::validate; -use crate::rita_common::peer_listener::get_peers; -use crate::rita_common::peer_listener::tick; -use crate::rita_common::rita_loop::set_gateway; -use crate::rita_common::traffic_watcher::{TrafficWatcher, Watch}; -use crate::rita_common::tunnel_manager::gc::TriggerGc; -use crate::rita_common::tunnel_manager::PeersToContact; -use crate::rita_common::tunnel_manager::{GetNeighbors, TunnelManager}; +use crate::blockchain_oracle::update as BlockchainOracleUpdate; +use crate::debt_keeper::send_debt_update; +use crate::network_monitor::NetworkInfo as NetworkMonitorTick; +use crate::network_monitor::NetworkMonitor; +use crate::payment_validator::validate; +use crate::peer_listener::get_peers; +use crate::peer_listener::tick; +use crate::rita_loop::set_gateway; +use crate::traffic_watcher::{TrafficWatcher, Watch}; +use crate::tunnel_manager::gc::TriggerGc; +use crate::tunnel_manager::PeersToContact; +use crate::tunnel_manager::{GetNeighbors, TunnelManager}; use crate::KI; -use crate::SETTING; use actix::{ Actor, ActorContext, Addr, Arbiter, AsyncContext, Context, Handler, Message, Supervised, System, SystemService, @@ -24,7 +23,7 @@ use babel_monitor_legacy::parse_routes_legacy; use babel_monitor_legacy::start_connection_legacy; use failure::Error; use futures01::Future; -use settings::RitaCommonSettings; + use std::thread; use std::time::{Duration, Instant}; @@ -91,7 +90,7 @@ impl Message for Tick { impl Handler for RitaFastLoop { type Result = Result<(), Error>; fn handle(&mut self, _: Tick, _ctx: &mut Context) -> Self::Result { - let babel_port = SETTING.get_network().babel_port; + let babel_port = settings::get_rita_common().get_network().babel_port; trace!("Common tick!"); manage_gateway(); @@ -277,7 +276,7 @@ fn manage_gateway() { // Background info here https://forum.altheamesh.com/t/the-gateway-client-corner-case/35 // the is_up detection is mostly useless because these ports reside on switches which mark // all ports as up all the time. - let gateway = match SETTING.get_network().external_nic { + let gateway = match settings::get_rita_common().get_network().external_nic { Some(ref external_nic) => KI.is_iface_up(external_nic).unwrap_or(false), None => false, }; @@ -290,8 +289,11 @@ fn manage_gateway() { Ok(s) => { for ip in s.iter() { trace!("Resolv route {:?}", ip); - KI.manual_peers_route(&ip, &mut SETTING.get_network_mut().last_default_route) - .unwrap(); + KI.manual_peers_route( + &ip, + &mut settings::get_rita_common().get_network().last_default_route, + ) + .unwrap(); } } Err(e) => warn!("Failed to add DNS routes with {:?}", e), diff --git a/rita/src/rita_common/rita_loop/mod.rs b/rita_common/src/rita_loop/mod.rs similarity index 70% rename from rita/src/rita_common/rita_loop/mod.rs rename to rita_common/src/rita_loop/mod.rs index ea80e57ad..0ef6cdd8d 100644 --- a/rita/src/rita_common/rita_loop/mod.rs +++ b/rita_common/src/rita_loop/mod.rs @@ -5,14 +5,12 @@ //! all system functions. Anything that blocks will eventually filter up to block this loop and //! halt essential functions like opening tunnels and managing peers -use crate::rita_common::network_endpoints::*; -use crate::SETTING; +use crate::network_endpoints::*; use actix::SystemService; use actix_web::http::Method; use actix_web::{server, App}; use rand::thread_rng; use rand::Rng; -use settings::RitaCommonSettings; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; @@ -41,10 +39,14 @@ pub fn set_gateway(input: bool) { /// one or more a random entry from the list is returned in an attempt /// to load balance across fullnodes pub fn get_web3_server() -> String { - if SETTING.get_payment().node_list.is_empty() { + if settings::get_rita_common() + .get_payment() + .node_list + .is_empty() + { panic!("no full nodes configured!"); } - let node_list = SETTING.get_payment().node_list.clone(); + let node_list = settings::get_rita_common().get_payment().node_list; let mut rng = thread_rng(); let val = rng.gen_range(0..node_list.len()); @@ -55,7 +57,10 @@ pub fn start_core_rita_endpoints(workers: usize) { // Rita hello function server::new(|| App::new().resource("/hello", |r| r.method(Method::POST).with(hello_response))) .workers(workers) - .bind(format!("[::0]:{}", SETTING.get_network().rita_hello_port)) + .bind(format!( + "[::0]:{}", + settings::get_rita_common().get_network().rita_hello_port + )) .unwrap() .shutdown_timeout(0) .start(); @@ -67,18 +72,21 @@ pub fn start_core_rita_endpoints(workers: usize) { }) }) .workers(workers) - .bind(format!("[::0]:{}", SETTING.get_network().rita_contact_port)) + .bind(format!( + "[::0]:{}", + settings::get_rita_common().get_network().rita_contact_port + )) .unwrap() .shutdown_timeout(0) .start(); } pub fn check_rita_common_actors() { - assert!(crate::rita_common::payment_controller::PaymentController::from_registry().connected()); - assert!(crate::rita_common::tunnel_manager::TunnelManager::from_registry().connected()); - assert!(crate::rita_common::hello_handler::HelloHandler::from_registry().connected()); - assert!(crate::rita_common::traffic_watcher::TrafficWatcher::from_registry().connected()); - assert!(crate::rita_common::rita_loop::fast_loop::RitaFastLoop::from_registry().connected()); - crate::rita_common::rita_loop::slow_loop::start_rita_slow_loop(); - crate::rita_common::rita_loop::fast_loop::start_rita_fast_loop(); + assert!(crate::payment_controller::PaymentController::from_registry().connected()); + assert!(crate::tunnel_manager::TunnelManager::from_registry().connected()); + assert!(crate::hello_handler::HelloHandler::from_registry().connected()); + assert!(crate::traffic_watcher::TrafficWatcher::from_registry().connected()); + assert!(crate::rita_loop::fast_loop::RitaFastLoop::from_registry().connected()); + crate::rita_loop::slow_loop::start_rita_slow_loop(); + crate::rita_loop::fast_loop::start_rita_fast_loop(); } diff --git a/rita/src/rita_common/rita_loop/slow_loop.rs b/rita_common/src/rita_loop/slow_loop.rs similarity index 88% rename from rita/src/rita_common/rita_loop/slow_loop.rs rename to rita_common/src/rita_loop/slow_loop.rs index 3a6fc8501..a95cde015 100644 --- a/rita/src/rita_common/rita_loop/slow_loop.rs +++ b/rita_common/src/rita_loop/slow_loop.rs @@ -1,8 +1,7 @@ -use crate::rita_common::simulated_txfee_manager::tick_simulated_tx; -use crate::rita_common::token_bridge::tick_token_bridge; -use crate::rita_common::utils::wait_timeout::wait_timeout; -use crate::rita_common::utils::wait_timeout::WaitResult; -use crate::SETTING; +use crate::simulated_txfee_manager::tick_simulated_tx; +use crate::token_bridge::tick_token_bridge; +use crate::utils::wait_timeout::wait_timeout; +use crate::utils::wait_timeout::WaitResult; use actix::System; use actix_async::System as AsyncSystem; // use babel_monitor::open_babel_stream; @@ -14,7 +13,7 @@ use babel_monitor_legacy::set_local_fee_legacy; use babel_monitor_legacy::set_metric_factor_legacy; use babel_monitor_legacy::start_connection_legacy; use futures01::future::Future; -use settings::RitaCommonSettings; + use std::thread; use std::time::Duration; use std::time::Instant; @@ -67,9 +66,9 @@ pub fn start_rita_slow_loop() { fn set_babel_price() { let start = Instant::now(); - let babel_port = SETTING.get_network().babel_port; - let local_fee = SETTING.get_payment().local_fee; - let metric_factor = SETTING.get_network().metric_factor; + let babel_port = settings::get_rita_common().get_network().babel_port; + let local_fee = settings::get_rita_common().get_payment().local_fee; + let metric_factor = settings::get_rita_common().get_network().metric_factor; let res = wait_timeout( open_babel_stream_legacy(babel_port) .from_err() diff --git a/rita/src/rita_common/simulated_txfee_manager/mod.rs b/rita_common/src/simulated_txfee_manager/mod.rs similarity index 89% rename from rita/src/rita_common/simulated_txfee_manager/mod.rs rename to rita_common/src/simulated_txfee_manager/mod.rs index 9b36d341a..c211280d7 100644 --- a/rita/src/rita_common/simulated_txfee_manager/mod.rs +++ b/rita_common/src/simulated_txfee_manager/mod.rs @@ -1,17 +1,15 @@ //! The maintainer fee is a fraction of all payments that is sent to the firmware maintainer -use crate::rita_common::payment_controller::TRANSACTION_SUBMISSION_TIMEOUT; -use crate::rita_common::rita_loop::get_web3_server; -use crate::rita_common::usage_tracker::update_payments; -use crate::SETTING; +use crate::payment_controller::TRANSACTION_SUBMISSION_TIMEOUT; +use crate::rita_loop::get_web3_server; +use crate::usage_tracker::update_payments; use althea_types::Identity; use althea_types::PaymentTx; use async_web30::client::Web3; use clarity::Transaction; use num256::Uint256; -use num_traits::Signed; -use num_traits::Zero; -use settings::RitaCommonSettings; +use num_traits::{Signed, Zero}; + use std::sync::Arc; use std::sync::RwLock; @@ -22,7 +20,11 @@ lazy_static! { // this is sent when a transaction is successful in another module and it registers // some amount to be paid as part of the fee pub fn add_tx_to_total(amount: Uint256) { - let to_add = amount / SETTING.get_payment().simulated_transaction_fee.into(); + let to_add = amount + / settings::get_rita_common() + .get_payment() + .simulated_transaction_fee + .into(); let mut amount_owed = AMOUNT_OWED.write().unwrap(); info!( "Simulated txfee total is {} with {} to add", @@ -32,9 +34,9 @@ pub fn add_tx_to_total(amount: Uint256) { } pub async fn tick_simulated_tx() { - let payment_settings = SETTING.get_payment(); + let payment_settings = settings::get_rita_common().get_payment(); let eth_private_key = payment_settings.eth_private_key; - let our_id = match SETTING.get_identity() { + let our_id = match settings::get_rita_common().get_identity() { Some(id) => id, None => return, }; diff --git a/rita/src/rita_common/token_bridge/mod.rs b/rita_common/src/token_bridge/mod.rs similarity index 89% rename from rita/src/rita_common/token_bridge/mod.rs rename to rita_common/src/token_bridge/mod.rs index f44a7ddbc..2e0ff014d 100644 --- a/rita/src/rita_common/token_bridge/mod.rs +++ b/rita_common/src/token_bridge/mod.rs @@ -1,49 +1,47 @@ -//! This module is designed to allow easy deposits for some supported chains using Ethereum. The idea -//! is pretty simple, the user deposits money into their routers Ethereum address, this is then exchanged -//! through uniswap into DAI and then from there it is bridged over to the Xdai proof of authority chains. -//! Support for Cosmos chains using a DAI-pegged native currency is next on the list. -//! -//! Essentially the goal is to allow users to deposit a popular and easy to acquire coin like Ethereum and then -//! actually transact in a stablecoin on a fast blockchain, eg not Ethereum. Withdraws are also transparently -//! converted back to Ethereum to allow easy exchange by the user. -//! -//! This entire module works on the premise we call the conveyor belt model. It's difficult to track -//! money through this entire process exactly, in fact there are some edge cases where it's simply not -//! possible to reliably say if a task has completed or not. With that in mind we simply always progress -//! the the process for Eth -> DAI -> XDAI unless we explicitly have a withdraw in progress. So if we find -//! some DAI in our address it will always be converted to XDAI even if we didn't convert that DAI from Eth -//! in the first place. -//! -//! For the withdraw process we create a withdraw request object which does a best effort shepherding of the -//! requested withdraw amount back to Eth and into the users hands. If this fails then the withdraw will timeout -//! and the money will not be lost but instead moved back into XDAI by the normal conveyor belt operation -//! -//! -//! TickEvent: -//! State::Ready: -//! If there is a Dai balance, send it thru the bridge into xdai (this rescues stuck funds in Dai) -//! -//! If there is an `eth_balance` that is greater than the `minimum_to_exchange` amount, -//! subtract the `reserve` amount and send it through uniswap into DAI. If not Change to State::Ready -//! Future waits on Uniswap, and upon successful swap, sends dai thru the bridge into xdai. -//! When the money is out of the Dai account and in the bridge, or if uniswap times out, change -//! to State::Ready. -//! -//! State::WithdrawRequest { to, amount, timestamp}: -//! Performs the initial send to the bridge, then progresses to State::Withdrawing, this is required -//! in order to ensure that we only send the funds for a given withdraw once -//! -//! State::Withdrawing { to, amount, timestamp}: -//! If the timestamp is expired, switch the state back into State::Ready. -//! -//! If there is a dai balance greater or equal to the withdraw amount, send the withdraw -//! amount through uniswap. -//! -//! Future waits on Uniswap and upon successful swap, sends eth to "to" address. Another future -//! waits on this transfer to complete. When it is complete, the state switches back to State::Ready - -use crate::rita_common::rita_loop::slow_loop::SLOW_LOOP_TIMEOUT; -use crate::SETTING; +// This module is designed to allow easy deposits for some supported chains using Ethereum. The idea +// is pretty simple, the user deposits money into their routers Ethereum address, this is then exchanged +// through uniswap into DAI and then from there it is bridged over to the Xdai proof of authority chains. +// Support for Cosmos chains using a DAI-pegged native currency is next on the list. + +// Essentially the goal is to allow users to deposit a popular and easy to acquire coin like Ethereum and then +// actually transact in a stablecoin on a fast blockchain, eg not Ethereum. Withdraws are also transparently +// converted back to Ethereum to allow easy exchange by the user. + +// This entire module works on the premise we call the conveyor belt model. It's difficult to track +// money through this entire process exactly, in fact there are some edge cases where it's simply not +// possible to reliably say if a task has completed or not. With that in mind we simply always progress +// the the process for Eth -> DAI -> XDAI unless we explicitly have a withdraw in progress. So if we find +// some DAI in our address it will always be converted to XDAI even if we didn't convert that DAI from Eth +// in the first place. + +// For the withdraw process we create a withdraw request object which does a best effort shepherding of the +// requested withdraw amount back to Eth and into the users hands. If this fails then the withdraw will timeout +// and the money will not be lost but instead moved back into XDAI by the normal conveyor belt operation + +// TickEvent: +// State::Ready: +// If there is a Dai balance, send it thru the bridge into xdai (this rescues stuck funds in Dai) + +// If there is an `eth_balance` that is greater than the `minimum_to_exchange` amount, +// subtract the `reserve` amount and send it through uniswap into DAI. If not Change to State::Ready +// Future waits on Uniswap, and upon successful swap, sends dai thru the bridge into xdai. +// When the money is out of the Dai account and in the bridge, or if uniswap times out, change +// to State::Ready. + +// State::WithdrawRequest { to, amount, timestamp}: +// Performs the initial send to the bridge, then progresses to State::Withdrawing, this is required +// in order to ensure that we only send the funds for a given withdraw once + +// State::Withdrawing { to, amount, timestamp}: +// If the timestamp is expired, switch the state back into State::Ready. + +// If there is a dai balance greater or equal to the withdraw amount, send the withdraw +// amount through uniswap. + +// Future waits on Uniswap and upon successful swap, sends eth to "to" address. Another future +// waits on this transfer to complete. When it is complete, the state switches back to State::Ready + +use crate::rita_loop::slow_loop::SLOW_LOOP_TIMEOUT; use althea_types::SystemChain; use async_web30::types::SendTxOption; use auto_bridge::ETH_TRANSACTION_GAS_LIMIT; @@ -51,11 +49,12 @@ use auto_bridge::UNISWAP_GAS_LIMIT; use auto_bridge::{HelperWithdrawInfo, ERC20_GAS_LIMIT}; use auto_bridge::{TokenBridge as TokenBridgeCore, TokenBridgeError}; use clarity::Address; -use failure::Error; +use failure::{bail, Error}; use num256::Uint256; use num_traits::identities::Zero; use rand::{thread_rng, Rng}; -use settings::{payment::PaymentSettings, RitaCommonSettings}; +use settings::payment::PaymentSettings; + use std::fmt; use std::fmt::Display; use std::sync::Arc; @@ -160,7 +159,7 @@ pub struct LastAmounts { pub async fn tick_token_bridge() { let bridge: TokenBridgeState = BRIDGE.read().unwrap().clone(); - let payment_settings = SETTING.get_payment(); + let payment_settings = settings::get_rita_common().get_payment(); let system_chain = payment_settings.system_chain; if !payment_settings.bridge_enabled { @@ -282,7 +281,10 @@ async fn eth_bridge() { if our_xdai_balance > xdai_tx_cost { let amount = our_xdai_balance - xdai_tx_cost; let res = bridge - .xdai_to_dai_bridge(amount.clone(), SETTING.get_payment().gas_price.clone()) + .xdai_to_dai_bridge( + amount.clone(), + settings::get_rita_common().get_payment().gas_price.clone(), + ) .await; if res.is_err() { warn!("Xdai to xdai failed with {:?}", res); @@ -410,7 +412,10 @@ async fn xdai_bridge(state: State) -> State { timestamp, withdraw_all, } => match bridge - .xdai_to_dai_bridge(amount.clone(), SETTING.get_payment().gas_price.clone()) + .xdai_to_dai_bridge( + amount.clone(), + settings::get_rita_common().get_payment().gas_price.clone(), + ) .await { Ok(bridge_tx_id) => { @@ -658,7 +663,7 @@ pub struct Withdraw { } pub fn withdraw(msg: Withdraw) -> Result<(), Error> { - let payment_settings = SETTING.get_payment(); + let payment_settings = settings::get_rita_common().get_payment(); let system_chain = payment_settings.system_chain; drop(payment_settings); let bridge = BRIDGE.read().unwrap().clone(); @@ -760,7 +765,7 @@ pub struct BridgeStatus { } pub fn get_bridge_status() -> BridgeStatus { - let payment_settings = SETTING.get_payment(); + let payment_settings = settings::get_rita_common().get_payment(); let withdraw_chain = payment_settings.withdraw_chain; drop(payment_settings); let bridge = BRIDGE.read().unwrap().clone(); @@ -778,7 +783,7 @@ pub fn get_bridge_status() -> BridgeStatus { /// Grab state parameters from settings fn get_core() -> TokenBridgeCore { - let payment_settings = SETTING.get_payment(); + let payment_settings = settings::get_rita_common().get_payment(); token_bridge_core_from_settings(&payment_settings) } diff --git a/rita/src/rita_common/traffic_watcher/mod.rs b/rita_common/src/traffic_watcher/mod.rs similarity index 95% rename from rita/src/rita_common/traffic_watcher/mod.rs rename to rita_common/src/traffic_watcher/mod.rs index 1c5a6da23..9d25f59cd 100644 --- a/rita/src/rita_common/traffic_watcher/mod.rs +++ b/rita_common/src/traffic_watcher/mod.rs @@ -2,22 +2,22 @@ //! iptables and ipset counters on each per hop tunnel (the WireGuard tunnel between two devices). These counts //! are then stored and used to compute amounts for bills. -use crate::rita_common::debt_keeper::traffic_update; -use crate::rita_common::debt_keeper::Traffic; -use crate::rita_common::tunnel_manager::Neighbor; -use crate::rita_common::usage_tracker::update_usage_data; -use crate::rita_common::usage_tracker::UpdateUsage; -use crate::rita_common::usage_tracker::UsageType; +use crate::debt_keeper::traffic_update; +use crate::debt_keeper::Traffic; +use crate::tunnel_manager::Neighbor; +use crate::usage_tracker::update_usage_data; +use crate::usage_tracker::UpdateUsage; +use crate::usage_tracker::UsageType; use crate::KI; -use crate::SETTING; -use ::actix::{Actor, Context, Handler, Message, Supervised, SystemService}; +use actix::{Actor, Context, Handler, Message, Supervised, SystemService}; use althea_kernel_interface::open_tunnel::is_link_local; use althea_kernel_interface::FilterTarget; use althea_types::Identity; use babel_monitor::Route as RouteLegacy; +use failure::bail; use failure::Error; use ipnetwork::IpNetwork; -use settings::RitaCommonSettings; + use std::collections::HashMap; use std::net::IpAddr; @@ -90,9 +90,9 @@ pub fn get_babel_info(routes: Vec) -> Result<(HashMap let mut destinations = HashMap::new(); // we assume this matches what is actually set it babel because we // panic on startup if it does not get set correctly - let local_fee = SETTING.get_payment().local_fee; + let local_fee = settings::get_rita_common().get_payment().local_fee; - let max_fee = SETTING.get_payment().max_fee; + let max_fee = settings::get_rita_common().get_payment().max_fee; for route in &routes { // Only ip6 if let IpNetwork::V6(ref ip) = route.prefix { @@ -114,7 +114,7 @@ pub fn get_babel_info(routes: Vec) -> Result<(HashMap } destinations.insert( - match SETTING.get_network().mesh_ip { + match settings::get_rita_common().get_network().mesh_ip { Some(ip) => ip, None => bail!("No mesh IP configured yet"), }, diff --git a/rita/src/rita_common/tunnel_manager/gc.rs b/rita_common/src/tunnel_manager/gc.rs similarity index 100% rename from rita/src/rita_common/tunnel_manager/gc.rs rename to rita_common/src/tunnel_manager/gc.rs diff --git a/rita/src/rita_common/tunnel_manager/id_callback.rs b/rita_common/src/tunnel_manager/id_callback.rs similarity index 93% rename from rita/src/rita_common/tunnel_manager/id_callback.rs rename to rita_common/src/tunnel_manager/id_callback.rs index c5f96a226..52ce99586 100644 --- a/rita/src/rita_common/tunnel_manager/id_callback.rs +++ b/rita_common/src/tunnel_manager/id_callback.rs @@ -1,6 +1,6 @@ -use crate::rita_common::peer_listener::Peer; -use crate::rita_common::tunnel_manager::Tunnel; -use crate::rita_common::tunnel_manager::TunnelManager; +use crate::peer_listener::Peer; +use crate::tunnel_manager::Tunnel; +use crate::tunnel_manager::TunnelManager; use actix::{Context, Handler, Message}; use althea_types::LocalIdentity; use std::net::Ipv4Addr; diff --git a/rita/src/rita_common/tunnel_manager/mod.rs b/rita_common/src/tunnel_manager/mod.rs similarity index 94% rename from rita/src/rita_common/tunnel_manager/mod.rs rename to rita_common/src/tunnel_manager/mod.rs index bdc621175..a756b5db5 100644 --- a/rita/src/rita_common/tunnel_manager/mod.rs +++ b/rita_common/src/tunnel_manager/mod.rs @@ -9,11 +9,10 @@ pub mod id_callback; pub mod neighbor_status; pub mod shaping; -use crate::rita_common; -use crate::rita_common::hello_handler::Hello; -use crate::rita_common::peer_listener::Peer; +use crate::hello_handler::Hello; +use crate::peer_listener::Peer; +use crate::rita_loop::is_gateway; use crate::KI; -use crate::SETTING; #[cfg(test)] use actix::actors::mocker::Mocker; use actix::actors::resolver; @@ -29,8 +28,7 @@ use failure::Error; use futures01::Future; use rand::thread_rng; use rand::Rng; -use rita_common::rita_loop::is_gateway; -use settings::RitaCommonSettings; + use std::collections::HashMap; use std::fmt; use std::fmt::Display; @@ -40,9 +38,9 @@ use std::time::{Duration, Instant}; use tokio::timer::Delay; #[cfg(test)] -type HelloHandler = Mocker; +type HelloHandler = Mocker; #[cfg(not(test))] -type HelloHandler = rita_common::hello_handler::HelloHandler; +type HelloHandler = crate::hello_handler::HelloHandler; #[cfg(test)] type Resolver = Mocker; #[cfg(not(test))] @@ -148,7 +146,7 @@ impl Tunnel { ) -> Result { let speed_limit = None; let iface_name = KI.setup_wg_if()?; - let mut network = SETTING.get_network_mut().clone(); + let mut network = settings::get_rita_common().get_network(); let args = TunnelOpenArgs { interface: iface_name.clone(), port: our_listen_port, @@ -201,7 +199,7 @@ impl Tunnel { pub fn monitor(&self, retry_count: u8) { info!("Monitoring tunnel {}", self.iface_name); let iface_name = self.iface_name.clone(); - let babel_port = SETTING.get_network().babel_port; + let babel_port = settings::get_rita_common().get_network().babel_port; let tunnel = self.clone(); Arbiter::spawn( @@ -237,7 +235,7 @@ impl Tunnel { pub fn unmonitor(&self, retry_count: u8) { warn!("Unmonitoring tunnel {}", self.iface_name); let iface_name = self.iface_name.clone(); - let babel_port = SETTING.get_network().babel_port; + let babel_port = settings::get_rita_common().get_network().babel_port; let tunnel = self.clone(); Arbiter::spawn( @@ -498,7 +496,7 @@ impl Message for PeersToContact { impl Handler for TunnelManager { type Result = (); fn handle(&mut self, msg: PeersToContact, _ctx: &mut Context) -> Self::Result { - let network_settings = SETTING.get_network(); + let network_settings = settings::get_rita_common().get_network(); let manual_peers = network_settings.manual_peers.clone(); let is_gateway = is_gateway(); let rita_hello_port = network_settings.rita_hello_port; @@ -552,14 +550,12 @@ impl Handler for TunnelManager { /// Sets out to contact a neighbor, takes a speculative port (only assigned if the neighbor /// responds successfully) fn contact_neighbor(peer: &Peer, our_port: u16) -> Result<(), Error> { - KI.manual_peers_route( - &peer.contact_socket.ip(), - &mut SETTING.get_network_mut().last_default_route, - )?; + let mut network = settings::get_rita_common().get_network(); + KI.manual_peers_route(&peer.contact_socket.ip(), &mut network.last_default_route)?; HelloHandler::from_registry().do_send(Hello { my_id: LocalIdentity { - global: SETTING + global: settings::get_rita_common() .get_identity() .ok_or_else(|| format_err!("Identity has no mesh IP ready yet"))?, wg_port: our_port, @@ -567,7 +563,6 @@ fn contact_neighbor(peer: &Peer, our_port: u16) -> Result<(), Error> { }, to: peer.clone(), }); - Ok(()) } @@ -608,7 +603,7 @@ fn del_tunnel(to_del: &Tunnel, tunnels: &mut Vec) { impl TunnelManager { pub fn new() -> Self { - let start = SETTING.get_network().wg_start_port; + let start = settings::get_rita_common().get_network().wg_start_port; let ports = (start..65535).collect(); TunnelManager { free_ports: ports, @@ -660,10 +655,9 @@ impl TunnelManager { /// callback continue execution flow. But this function itself returns syncronously pub fn neighbor_inquiry_hostname(&mut self, their_hostname: String) -> Result<(), Error> { trace!("Getting tunnel, inq"); - let network_settings = SETTING.get_network(); + let network_settings = settings::get_rita_common().get_network(); let is_gateway = is_gateway(); let rita_hello_port = network_settings.rita_hello_port; - drop(network_settings); let our_port = match self.get_port(0) { Some(p) => p, @@ -1003,9 +997,14 @@ fn tunnel_bw_limit_update(tunnels: &HashMap>) -> Result<() } } let bw_per_iface = if limited_interfaces > 0 { - SETTING.get_payment().free_tier_throughput / u32::from(limited_interfaces) + settings::get_rita_common() + .get_payment() + .free_tier_throughput + / u32::from(limited_interfaces) } else { - SETTING.get_payment().free_tier_throughput + settings::get_rita_common() + .get_payment() + .free_tier_throughput }; for sublist in tunnels.iter() { @@ -1024,15 +1023,46 @@ fn tunnel_bw_limit_update(tunnels: &HashMap>) -> Result<() Ok(()) } +pub fn get_test_id() -> Identity { + Identity { + mesh_ip: "::1".parse().unwrap(), + eth_address: "0x4288C538A553357Bb6c3b77Cf1A60Da6E77931F6" + .parse() + .unwrap(), + wg_public_key: "GIaAXDi1PbGq3PsKqBnT6kIPoE2K1Ssv9HSb7++dzl4=" + .parse() + .unwrap(), + nickname: None, + } +} + +pub fn get_test_tunnel(ip: Ipv4Addr, light: bool) -> Tunnel { + let light_client_details = if light { Some(ip) } else { None }; + Tunnel { + ip: ip.into(), + iface_name: "iface".to_string(), + listen_ifidx: 0, + listen_port: 65535, + neigh_id: LocalIdentity { + wg_port: 65535, + have_tunnel: Some(true), + global: get_test_id(), + }, + last_contact: Instant::now(), + created: Instant::now(), + speed_limit: None, + light_client_details, + payment_state: PaymentState::Paid, + } +} + #[cfg(test)] pub mod tests { use super::PaymentState; - use crate::rita_common::tunnel_manager::Tunnel; - use crate::rita_common::tunnel_manager::TunnelManager; + use crate::tunnel_manager::get_test_tunnel; + use crate::tunnel_manager::Tunnel; + use crate::tunnel_manager::TunnelManager; use althea_types::Identity; - use althea_types::LocalIdentity; - use std::net::Ipv4Addr; - use std::time::Instant; /// gets a mutable reference tunnel from the list with the given index fn get_mut_tunnel_by_ifidx(ifidx: u32, tunnels: &mut Vec) -> Option<&mut Tunnel> { @@ -1050,39 +1080,6 @@ pub mod tests { assert_eq!(tunnel_manager.free_ports.pop().unwrap(), 65534); } - pub fn get_test_id() -> Identity { - Identity { - mesh_ip: "::1".parse().unwrap(), - eth_address: "0x4288C538A553357Bb6c3b77Cf1A60Da6E77931F6" - .parse() - .unwrap(), - wg_public_key: "GIaAXDi1PbGq3PsKqBnT6kIPoE2K1Ssv9HSb7++dzl4=" - .parse() - .unwrap(), - nickname: None, - } - } - - pub fn get_test_tunnel(ip: Ipv4Addr, light: bool) -> Tunnel { - let light_client_details = if light { Some(ip) } else { None }; - Tunnel { - ip: ip.into(), - iface_name: "iface".to_string(), - listen_ifidx: 0, - listen_port: 65535, - neigh_id: LocalIdentity { - wg_port: 65535, - have_tunnel: Some(true), - global: get_test_id(), - }, - last_contact: Instant::now(), - created: Instant::now(), - speed_limit: None, - light_client_details, - payment_state: PaymentState::Paid, - } - } - #[test] pub fn test_tunnel_manager_lookup() { use clarity::Address; diff --git a/rita/src/rita_common/tunnel_manager/neighbor_status.rs b/rita_common/src/tunnel_manager/neighbor_status.rs similarity index 100% rename from rita/src/rita_common/tunnel_manager/neighbor_status.rs rename to rita_common/src/tunnel_manager/neighbor_status.rs diff --git a/rita/src/rita_common/tunnel_manager/shaping.rs b/rita_common/src/tunnel_manager/shaping.rs similarity index 97% rename from rita/src/rita_common/tunnel_manager/shaping.rs rename to rita_common/src/tunnel_manager/shaping.rs index c58f13128..0b616c658 100644 --- a/rita/src/rita_common/tunnel_manager/shaping.rs +++ b/rita_common/src/tunnel_manager/shaping.rs @@ -1,8 +1,6 @@ use super::TunnelManager; use crate::KI; -use crate::SETTING; use actix::{Context, Handler, Message}; -use settings::RitaCommonSettings; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; @@ -39,11 +37,10 @@ impl Handler for TunnelManager { type Result = (); fn handle(&mut self, msg: ShapeMany, _: &mut Context) -> Self::Result { - let network_settings = SETTING.get_network(); + let network_settings = settings::get_rita_common().get_network(); let minimum_bandwidth_limit = network_settings.shaper_settings.min_speed; let starting_bandwidth_limit = network_settings.shaper_settings.max_speed; let bandwidth_limit_enabled = network_settings.shaper_settings.enabled; - drop(network_settings); // removes shaping without requiring a restart if the flag is set or // if it's set in the settings diff --git a/rita_common/src/tunnel_manager/tests.rs b/rita_common/src/tunnel_manager/tests.rs new file mode 100644 index 000000000..e69de29bb diff --git a/rita/src/rita_common/usage_tracker/mod.rs b/rita_common/src/usage_tracker/mod.rs similarity index 98% rename from rita/src/rita_common/usage_tracker/mod.rs rename to rita_common/src/usage_tracker/mod.rs index ac8ccbe1f..14067d836 100644 --- a/rita/src/rita_common/usage_tracker/mod.rs +++ b/rita_common/src/usage_tracker/mod.rs @@ -4,7 +4,6 @@ //! the handler updates the storage to reflect the new total. When a user would like to inspect //! or graph usage they query an endpoint which will request the data from this module. -use crate::SETTING; use actix::Message; use althea_types::Identity; use althea_types::PaymentTx; @@ -15,7 +14,6 @@ use flate2::Compression; use num256::Uint256; use serde::{Deserialize, Serialize}; use serde_json::Error as SerdeError; -use settings::RitaCommonSettings; use std::collections::VecDeque; use std::fs::File; use std::io; @@ -141,7 +139,7 @@ impl UsageTrackerMisspelled { impl Default for UsageTracker { fn default() -> UsageTracker { - let file = File::open(SETTING.get_network().usage_tracker_file.clone()); + let file = File::open(settings::get_rita_common().get_network().usage_tracker_file); // if the loading process goes wrong for any reason, we just start again let blank_usage_tracker = UsageTracker { last_save_hour: 0, @@ -235,7 +233,7 @@ impl Default for UsageTracker { impl UsageTracker { fn save(&mut self) -> Result<(), IOError> { let serialized = serde_json::to_vec(self)?; - let mut file = File::create(SETTING.get_network().usage_tracker_file.clone())?; + let mut file = File::create(settings::get_rita_common().get_network().usage_tracker_file)?; let buffer: Vec = Vec::new(); let mut encoder = ZlibEncoder::new(buffer, Compression::fast()); encoder.write_all(&serialized)?; diff --git a/rita/src/rita_common/utils/ip_increment.rs b/rita_common/src/utils/ip_increment.rs similarity index 100% rename from rita/src/rita_common/utils/ip_increment.rs rename to rita_common/src/utils/ip_increment.rs diff --git a/rita/src/rita_common/utils/mod.rs b/rita_common/src/utils/mod.rs similarity index 100% rename from rita/src/rita_common/utils/mod.rs rename to rita_common/src/utils/mod.rs diff --git a/rita/src/rita_common/utils/wait_timeout.rs b/rita_common/src/utils/wait_timeout.rs similarity index 100% rename from rita/src/rita_common/utils/wait_timeout.rs rename to rita_common/src/utils/wait_timeout.rs diff --git a/rita_exit/Cargo.toml b/rita_exit/Cargo.toml new file mode 100644 index 000000000..c63e87f78 --- /dev/null +++ b/rita_exit/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "rita_exit" +version = "0.18.0" +edition = "2018" +license = "Apache-2.0" + +[lib] + + +[dependencies] +compressed_log = "0.3.4" +sodiumoxide = "0.2" +num256 = "0.3" +rita_common = { path = "../rita_common" } +althea_kernel_interface = { path = "../althea_kernel_interface" } +althea_types = { path = "../althea_types" } +settings = { path = "../settings" } +babel_monitor = { path = "../babel_monitor" } +actix = "0.7" +handlebars = "4.0" +rand = "0.8.0" +lazy_static = "1.4" +ipnetwork = "0.14" +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0" +lettre = "0.9" +lettre_email = "0.9" +r2d2 = "0.8" +phonenumber = "0.3" +failure = "0.1" +arrayvec = {version= "0.7", features = ["serde"]} +log = { version = "0.4", features = ["release_max_level_info"] } +reqwest = { version = "0.11", features = ["blocking", "json"] } +exit_db = { path = "../exit_db" } + +babel_monitor_legacy = {path = "../babel_monitor_legacy"} + +actix-web-httpauth = {git = "https://github.com/althea-net/actix-web-httpauth"} +actix-web = { version = "0.7", default_features = false, features= ["ssl"] } + +diesel = { version = "1.4", features = ["postgres", "r2d2"] } +futures01 = { package = "futures", version = "0.1"} \ No newline at end of file diff --git a/rita/src/rita_exit/database/database_tools.rs b/rita_exit/src/database/database_tools.rs similarity index 97% rename from rita/src/rita_exit/database/database_tools.rs rename to rita_exit/src/database/database_tools.rs index 5bffec6b9..2429264e8 100644 --- a/rita/src/rita_exit/database/database_tools.rs +++ b/rita_exit/src/database/database_tools.rs @@ -1,9 +1,11 @@ -use crate::rita_common::utils::ip_increment::increment; -use crate::rita_exit::database::secs_since_unix_epoch; -use crate::rita_exit::database::struct_tools::client_to_new_db_client; -use crate::rita_exit::database::ONE_DAY; +use crate::database::secs_since_unix_epoch; +use crate::database::struct_tools::client_to_new_db_client; +use crate::database::ONE_DAY; +use failure::bail; +use failure::format_err; +use rita_common::utils::ip_increment::increment; + use crate::DB_POOL; -use crate::SETTING; use actix_web::Result; use althea_kernel_interface::ExitClient; use althea_types::ExitClientIdentity; @@ -16,7 +18,6 @@ use exit_db::{models, schema}; use failure::Error; use futures01::future; use futures01::future::Future; -use settings::exit::RitaExitSettings; use std::net::IpAddr; use std::net::Ipv4Addr; @@ -40,7 +41,8 @@ fn get_internal_ips(clients: &[exit_db::models::Client]) -> Vec { /// sorting on the database side but I've left that optimization on the vine for now pub fn get_next_client_ip(conn: &PgConnection) -> Result { use self::schema::clients::dsl::clients; - let exit_settings = SETTING.get_exit_network(); + let rita_exit = settings::get_rita_exit(); + let exit_settings = rita_exit.exit_network; let netmask = exit_settings.netmask as u8; let start_ip = exit_settings.exit_start_ip; let gateway_ip = exit_settings.own_internal_ip; diff --git a/rita/src/rita_exit/database/db_client.rs b/rita_exit/src/database/db_client.rs similarity index 95% rename from rita/src/rita_exit/database/db_client.rs rename to rita_exit/src/database/db_client.rs index 51fde78a4..9fc9a4d67 100644 --- a/rita/src/rita_exit/database/db_client.rs +++ b/rita_exit/src/database/db_client.rs @@ -1,4 +1,3 @@ -use crate::rita_exit::database::get_database_connection; use actix::Actor; use actix::Arbiter; use actix::Context; @@ -13,6 +12,8 @@ use exit_db::schema; use failure::Error; use futures01::future::Future; +use crate::database::database_tools::get_database_connection; + #[derive(Default)] pub struct DbClient; diff --git a/rita/src/rita_exit/database/email.rs b/rita_exit/src/database/email.rs similarity index 90% rename from rita/src/rita_exit/database/email.rs rename to rita_exit/src/database/email.rs index fc3e83a2d..1253caf4c 100644 --- a/rita/src/rita_exit/database/email.rs +++ b/rita_exit/src/database/email.rs @@ -1,12 +1,14 @@ -use crate::rita_exit::database::database_tools::update_mail_sent_time; -use crate::rita_exit::database::database_tools::verify_client; -use crate::rita_exit::database::get_exit_info; -use crate::rita_exit::database::secs_since_unix_epoch; -use crate::rita_exit::database::struct_tools::verif_done; -use crate::SETTING; +use crate::database::database_tools::update_mail_sent_time; +use crate::database::database_tools::verify_client; +use crate::database::get_exit_info; +use crate::database::secs_since_unix_epoch; +use crate::database::struct_tools::verif_done; + use althea_types::{ExitClientDetails, ExitClientIdentity, ExitState}; use diesel::prelude::PgConnection; use exit_db::models; +use failure::bail; +use failure::format_err; use failure::Error; use futures01::future; use futures01::future::Future; @@ -17,11 +19,11 @@ use lettre::smtp::extension::ClientId; use lettre::smtp::ConnectionReuseParameters; use lettre::{SmtpClient, Transport}; use lettre_email::EmailBuilder; +use serde_json::json; use settings::exit::ExitVerifSettings; -use settings::exit::RitaExitSettings; pub fn send_mail(client: &models::Client) -> Result<(), Error> { - let mailer = match SETTING.get_verif_settings() { + let mailer = match settings::get_rita_exit().verif_settings { Some(ExitVerifSettings::Email(mailer)) => mailer, Some(_) => bail!("Verification mode is not email!"), None => bail!("No verification mode configured!"), diff --git a/rita_exit/src/database/geoip.rs b/rita_exit/src/database/geoip.rs new file mode 100644 index 000000000..c8f7c8f7d --- /dev/null +++ b/rita_exit/src/database/geoip.rs @@ -0,0 +1,261 @@ +use babel_monitor_legacy::open_babel_stream_legacy; +use babel_monitor_legacy::parse_routes_legacy; +use babel_monitor_legacy::start_connection_legacy; +use failure::bail; +use failure::Error; +use futures01::future; +use futures01::future::Future; +use ipnetwork::IpNetwork; +use rita_common::utils::ip_increment::is_unicast_link_local; +use rita_common::KI; +use std::collections::HashMap; +use std::net::IpAddr; +use std::sync::{Arc, RwLock}; +use std::time::Duration; + +lazy_static! { + static ref GEOIP_CACHE: Arc>> = + Arc::new(RwLock::new(HashMap::new())); +} + +/// gets the gateway ip for a given mesh IP +pub fn get_gateway_ip_single(mesh_ip: IpAddr) -> Box> { + let babel_port = settings::get_rita_exit().network.babel_port; + + Box::new( + open_babel_stream_legacy(babel_port) + .from_err() + .and_then(move |stream| { + start_connection_legacy(stream).and_then(move |stream| { + parse_routes_legacy(stream).and_then(move |routes| { + let mut route_to_des = None; + for route in routes.1.iter() { + // Only ip6 + if let IpNetwork::V6(ref ip) = route.prefix { + // Only host addresses and installed routes + if ip.prefix() == 128 + && route.installed + && IpAddr::V6(ip.ip()) == mesh_ip + { + route_to_des = Some(route.clone()); + } + } + } + + match route_to_des { + Some(route) => Ok(KI.get_wg_remote_ip(&route.iface)?), + None => bail!("No route found for mesh ip: {:?}", mesh_ip), + } + }) + }) + }), + ) +} + +#[derive(Debug, Clone, Copy)] +pub struct IpPair { + pub mesh_ip: IpAddr, + pub gateway_ip: IpAddr, +} + +/// gets the gateway ip for a given set of mesh IPs, inactive addresses will simply +/// not appear in the result vec +pub fn get_gateway_ip_bulk( + mesh_ip_list: Vec, +) -> Box, Error = Error>> { + let babel_port = settings::get_rita_exit().network.babel_port; + trace!("getting gateway ip bulk"); + + Box::new( + open_babel_stream_legacy(babel_port) + .from_err() + .and_then(|stream| { + start_connection_legacy(stream).and_then(|stream| { + parse_routes_legacy(stream).and_then(|routes| { + trace!("done talking to babel for gateway ip bulk"); + let mut remote_ip_cache: HashMap = HashMap::new(); + let mut results = Vec::new(); + for mesh_ip in mesh_ip_list { + for route in routes.1.iter() { + // Only ip6 + if let IpNetwork::V6(ref ip) = route.prefix { + // Only host addresses and installed routes + if ip.prefix() == 128 + && route.installed + && IpAddr::V6(ip.ip()) == mesh_ip + { + // check if we've already looked up this interface this round, since gateways + // have many clients this will often be the case + if let Some(remote_ip) = remote_ip_cache.get(&route.iface) { + results.push(IpPair { + mesh_ip, + gateway_ip: *remote_ip, + }); + } else { + match KI.get_wg_remote_ip(&route.iface) { + Ok(remote_ip) => { + remote_ip_cache + .insert(route.iface.clone(), remote_ip); + results.push(IpPair { + mesh_ip, + gateway_ip: remote_ip, + }) + } + Err(e) => { + error!("Failure looking up remote ip {:?}", e) + } + } + } + } + } + } + } + + Ok(results) + }) + }) + }), + ) +} + +#[derive(Deserialize, Debug)] +struct GeoIpRet { + country: CountryDetails, +} + +#[derive(Deserialize, Debug)] +struct CountryDetails { + iso_code: String, +} + +pub fn get_country_async(ip: IpAddr) -> impl Future { + match get_country(ip) { + Ok(res) => future::ok(res), + Err(e) => future::err(e), + } +} + +/// get ISO country code from ip, consults a in memory cache +pub fn get_country(ip: IpAddr) -> Result { + trace!("get GeoIP country for {}", ip.to_string()); + + // if allowed countries is not configured we don't care and will insert + // empty stings into the DB. + if settings::get_rita_exit().allowed_countries.is_empty() { + return Ok(String::new()); + } + + // in this case we have a gateway directly attached to the exit, so our + // peer address for them will be an fe80 linklocal ip address. When we + // detect this we go ahead and assign the user one of our allowed countries + // and move on. In the common case where we have only one allowed country + // this will produce the correct result. We can affirm this will never panic + // because we just checked that allowed countries contains at least one value + // above + if let IpAddr::V6(val) = ip { + if is_unicast_link_local(&val) { + return Ok(settings::get_rita_exit() + .allowed_countries + .iter() + .next() + .unwrap() + .clone()); + } + } + + // on the other hand if there is a configured list of allowed countries + // but no configured api details, we panic + let api_user = settings::get_rita_exit() + .exit_network + .geoip_api_user + .expect("No api key configured!"); + let api_key = settings::get_rita_exit() + .exit_network + .geoip_api_key + .expect("No api key configured!"); + + // we have to turn this option into a string in order to avoid + // the borrow checker trying to keep this lock open for a long period + let cache_result = GEOIP_CACHE + .read() + .unwrap() + .get(&ip) + .map(|val| val.to_string()); + + match cache_result { + Some(code) => Ok(code), + None => { + let geo_ip_url = format!("https://geoip.maxmind.com/geoip/v2.1/country/{}", ip); + info!( + "making GeoIP request to {} for {}", + geo_ip_url, + ip.to_string() + ); + let client = reqwest::blocking::Client::new(); + if let Ok(res) = client + .get(&geo_ip_url) + .basic_auth(api_user, Some(api_key)) + .timeout(Duration::from_secs(1)) + .send() + { + trace!("Got geoip result {:?}", res); + if let Ok(res) = res.json() { + let value: GeoIpRet = res; + let code = value.country.iso_code; + trace!("Adding GeoIP value {:?} to cache", code); + GEOIP_CACHE.write().unwrap().insert(ip, code.clone()); + trace!("Added to cache, returning"); + Ok(code) + } else { + Err(format_err!("Failed to deserialize geoip response")) + } + } else { + Err(format_err!("request failed")) + } + } + } +} + +/// Returns true or false if an ip is confirmed to be inside or outside the region and error +/// if an api error is encountered trying to figure that out. +pub fn verify_ip(request_ip: IpAddr) -> impl Future { + match verify_ip_sync(request_ip) { + Ok(item) => future::ok(item), + Err(e) => future::err(e), + } +} + +/// Returns true or false if an ip is confirmed to be inside or outside the region and error +/// if an api error is encountered trying to figure that out. +pub fn verify_ip_sync(request_ip: IpAddr) -> Result { + // in this case we have a gateway directly attached to the exit, so our + // peer address for them will be an fe80 linklocal ip address. When we + // detect this we know that they are in the allowed countries list because + // we assume the exit itself is in one of it's allowed countries. + if let IpAddr::V6(val) = request_ip { + if is_unicast_link_local(&val) { + return Ok(true); + } + } + + if settings::get_rita_exit().allowed_countries.is_empty() { + Ok(true) + } else { + let country = get_country(request_ip)?; + if !settings::get_rita_exit().allowed_countries.is_empty() + && !settings::get_rita_exit() + .allowed_countries + .contains(&country) + { + return Ok(false); + } + + Ok(true) + } +} + +#[test] +#[ignore] +fn test_get_country() { + get_country("8.8.8.8".parse().unwrap()).unwrap(); +} diff --git a/rita/src/rita_exit/database/mod.rs b/rita_exit/src/database/mod.rs similarity index 71% rename from rita/src/rita_exit/database/mod.rs rename to rita_exit/src/database/mod.rs index 7b146e68a..b408b5005 100644 --- a/rita/src/rita_exit/database/mod.rs +++ b/rita_exit/src/database/mod.rs @@ -2,57 +2,62 @@ //! for the exit, which is most exit logic in general. Keep in mind database connections are remote //! and therefore synchronous database requests are quite expensive (on the order of tens of milliseconds) -use crate::rita_common::debt_keeper::get_debts_list; -use crate::rita_common::debt_keeper::DebtAction; -use crate::rita_exit::database::database_tools::client_conflict; -use crate::rita_exit::database::database_tools::create_or_update_user_record; -use crate::rita_exit::database::database_tools::delete_client; -use crate::rita_exit::database::database_tools::get_client; -use crate::rita_exit::database::database_tools::get_database_connection; -use crate::rita_exit::database::database_tools::get_database_connection_sync; -use crate::rita_exit::database::database_tools::set_client_timestamp; -use crate::rita_exit::database::database_tools::update_client; -use crate::rita_exit::database::database_tools::verify_client; -use crate::rita_exit::database::database_tools::verify_db_client; -use crate::rita_exit::database::email::handle_email_registration; -use crate::rita_exit::database::geoip::get_country; -use crate::rita_exit::database::geoip::get_gateway_ip_bulk; -use crate::rita_exit::database::geoip::get_gateway_ip_single; -use crate::rita_exit::database::geoip::verify_ip; -use crate::rita_exit::database::sms::handle_sms_registration; -use crate::rita_exit::database::struct_tools::display_hashset; -use crate::rita_exit::database::struct_tools::to_exit_client; -use crate::rita_exit::database::struct_tools::to_identity; -use crate::rita_exit::database::struct_tools::verif_done; -use crate::EXIT_ALLOWED_COUNTRIES; -use crate::EXIT_DESCRIPTION; -use crate::EXIT_NETWORK_SETTINGS; -use crate::EXIT_PRICE; -use crate::EXIT_SYSTEM_CHAIN; -use crate::EXIT_VERIF_SETTINGS; -use crate::KI; -use crate::SETTING; +use crate::create_or_update_user_record; +use crate::database::database_tools::client_conflict; +use crate::database::database_tools::delete_client; +use crate::database::database_tools::get_client; +use crate::database::database_tools::get_database_connection; +use crate::database::database_tools::set_client_timestamp; +use crate::database::database_tools::update_client; +use crate::database::database_tools::verify_client; +use crate::database::database_tools::verify_db_client; +use crate::database::email::handle_email_registration; +use crate::database::geoip::get_country_async; +use crate::database::geoip::get_gateway_ip_bulk; +use crate::database::geoip::get_gateway_ip_single; +use crate::database::geoip::verify_ip; +use crate::database::geoip::verify_ip_sync; +use crate::database::sms::handle_sms_registration; +use crate::database::struct_tools::display_hashset; +use crate::database::struct_tools::to_exit_client; +use crate::database::struct_tools::to_identity; +use crate::database::struct_tools::verif_done; +use crate::rita_loop::EXIT_LOOP_TIMEOUT; + use althea_kernel_interface::ExitClient; use althea_types::Identity; use althea_types::{ExitClientDetails, ExitClientIdentity, ExitDetails, ExitState, ExitVerifMode}; use diesel::prelude::PgConnection; +use failure::bail; +use failure::format_err; use failure::Error; use futures01::future; use futures01::Future; use ipnetwork::IpNetwork; +use rita_common::debt_keeper::get_debts_list; +use rita_common::debt_keeper::DebtAction; +use rita_common::utils::wait_timeout::wait_timeout; +use rita_common::utils::wait_timeout::WaitResult; use settings::exit::ExitVerifSettings; -use settings::exit::RitaExitSettings; -use settings::RitaCommonSettings; use std::collections::HashMap; use std::collections::HashSet; use std::net::IpAddr; use std::time::Instant; use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use crate::EXIT_ALLOWED_COUNTRIES; +use crate::EXIT_DESCRIPTION; +use crate::EXIT_NETWORK_SETTINGS; +use crate::EXIT_PRICE; +use crate::EXIT_SYSTEM_CHAIN; +use crate::EXIT_VERIF_SETTINGS; + +use rita_common::KI; + pub mod database_tools; pub mod db_client; -mod email; -mod geoip; +pub mod email; +pub mod geoip; pub mod sms; pub mod struct_tools; @@ -65,7 +70,7 @@ pub fn get_exit_info() -> ExitDetails { if Instant::now() > last_update && ((Instant::now() - last_update) > UPDATE_INTERVAL) { let mut exit_price = EXIT_PRICE.write().unwrap(); let old_exit_price = exit_price.0; - exit_price.0 = SETTING.get_exit_network().exit_price; + exit_price.0 = settings::get_rita_exit().exit_network.exit_price; exit_price.1 = Instant::now(); info!( "Updated exit price from settings {} -> {}", @@ -104,94 +109,77 @@ pub fn secs_since_unix_epoch() -> i64 { /// ip and then sends out an email of phone message pub fn signup_client(client: ExitClientIdentity) -> impl Future { info!("got setup request {:?}", client); - let gateway_ip = match get_gateway_ip_single(client.global.mesh_ip) { - Ok(a) => a, - Err(e) => { - return Box::new(future::err(e)) as Box> - } - }; - - info!("got gateway ip {:?}", client); - let verify_status = match verify_ip(gateway_ip) { - Ok(a) => a, - Err(e) => { - return Box::new(future::err(e)) as Box> - } - }; - - info!("verified the ip country {:?}", client); - let user_country = match get_country(gateway_ip) { - Ok(a) => a, - Err(e) => { - return Box::new(future::err(e)) as Box> - } - }; - - info!("got the country {:?}", client); + get_gateway_ip_single(client.global.mesh_ip).and_then(move |gateway_ip| { + info!("got gateway ip {:?}", client); + verify_ip(gateway_ip).and_then(move |verify_status| { + info!("verified the ip country {:?}", client); + get_country_async(gateway_ip).and_then(move |user_country| { + info!("got the country {:?}", client); + get_database_connection().and_then(move |conn| { + info!("Doing database work for {:?} in country {} with verify_status {}", client, user_country, verify_status); + // check if we have any users with conflicting details + match client_conflict(&client, &conn) { + Ok(true) => { + return Box::new(future::ok(ExitState::Denied { + message: format!( + "Partially changed registration details! Please reset your router and re-register with all new details. Backup your key first! {}", + display_hashset(&*EXIT_ALLOWED_COUNTRIES), + ), + })) + as Box> + } + Ok(false) => {} + Err(e) => return Box::new(future::err(e)), + } - let conn = match get_database_connection_sync() { - Ok(a) => a, - Err(e) => return Box::new(future::err(e)), - }; + let their_record = + match create_or_update_user_record(&conn, &client, user_country) { + Ok(record) => record, + Err(e) => return Box::new(future::err(e)), + }; - info!( - "Doing database work for {:?} in country {} with verify_status {}", - client, user_country, verify_status - ); - // check if we have any users with conflicting details - match client_conflict(&client, &conn) { - Ok(true) => { - return Box::new(future::ok(ExitState::Denied { - message: format!( - "Partially changed registration details! Please reset your router and re-register with all new details. Backup your key first! {}", - display_hashset(&*EXIT_ALLOWED_COUNTRIES), - ), - })) - as Box> - } - Ok(false) => {} - Err(e) => return Box::new(future::err(e)), - } - let their_record = match create_or_update_user_record(&conn, &client, user_country) { - Ok(record) => record, - Err(e) => return Box::new(future::err(e)), - }; - // either update and grab an existing entry or create one - match (verify_status, EXIT_VERIF_SETTINGS.clone()) { - (true, Some(ExitVerifSettings::Email(mailer))) => Box::new(handle_email_registration( - &client, - &their_record, - &conn, - mailer.email_cooldown as i64, - )), - (true, Some(ExitVerifSettings::Phone(phone))) => Box::new(handle_sms_registration( - client, - their_record, - phone.auth_api_key, - )), - (true, None) => { - match verify_client(&client, true, &conn) { - Ok(_) => (), - Err(e) => return Box::new(future::err(e)), - } - let client_internal_ip = match their_record.internal_ip.parse() { - Ok(ip) => ip, - Err(e) => return Box::new(future::err(format_err!("{:?}", e))), - }; - Box::new(future::ok(ExitState::Registered { - our_details: ExitClientDetails { client_internal_ip }, - general_details: get_exit_info(), - message: "Registration OK".to_string(), - })) - } - (false, _) => Box::new(future::ok(ExitState::Denied { - message: format!( - "This exit only accepts connections from {}", - display_hashset(&*EXIT_ALLOWED_COUNTRIES), - ), - })), - } + // either update and grab an existing entry or create one + match (verify_status, EXIT_VERIF_SETTINGS.clone()) { + (true, Some(ExitVerifSettings::Email(mailer))) => { + Box::new(handle_email_registration( + &client, + &their_record, + &conn, + mailer.email_cooldown as i64, + )) + } + (true, Some(ExitVerifSettings::Phone(phone))) => Box::new( + handle_sms_registration(client, their_record, phone.auth_api_key), + ), + (true, None) => { + match verify_client(&client, true, &conn) { + Ok(_) => (), + Err(e) => return Box::new(future::err(e)), + } + let client_internal_ip = match their_record.internal_ip.parse() { + Ok(ip) => ip, + Err(e) => return Box::new(future::err(format_err!("{:?}", e))), + }; + + Box::new(future::ok(ExitState::Registered { + our_details: ExitClientDetails { client_internal_ip }, + general_details: get_exit_info(), + message: "Registration OK".to_string(), + })) + } + (false, _) => Box::new(future::ok(ExitState::Denied { + message: format!( + "This exit only accepts connections from {}", + display_hashset(&*EXIT_ALLOWED_COUNTRIES), + ), + })), + } + }) + }) + }) + }) } + /// Gets the status of a client and updates it in the database pub fn client_status(client: ExitClientIdentity, conn: &PgConnection) -> Result { trace!("Checking if record exists for {:?}", client.global.mesh_ip); @@ -265,9 +253,13 @@ pub fn validate_clients_region( Err(_e) => error!("Database entry with invalid mesh ip! {:?}", item), } } - let list = get_gateway_ip_bulk(ip_vec)?; + let list = match wait_timeout(get_gateway_ip_bulk(ip_vec), EXIT_LOOP_TIMEOUT) { + WaitResult::Err(e) => return Err(e), + WaitResult::Ok(val) => val, + WaitResult::TimedOut(_) => return Err(format_err!("Timed out!")), + }; for item in list.iter() { - let res = verify_ip(item.gateway_ip); + let res = verify_ip_sync(item.gateway_ip); match res { Ok(true) => trace!("{:?} is from an allowed ip", item), Ok(false) => { @@ -309,7 +301,7 @@ pub fn cleanup_exit_clients( match to_exit_client(client.clone()) { Ok(client_id) => { let time_delta = secs_since_unix_epoch() - client.last_seen; - let entry_timeout = i64::from(SETTING.get_exit_network().entry_timeout); + let entry_timeout = i64::from(settings::get_rita_exit().exit_network.entry_timeout); // entry timeout can be disabled, or longer than a day, but not shorter assert!(entry_timeout == 0 || entry_timeout >= ONE_DAY); if client.last_seen == 0 { @@ -391,8 +383,8 @@ pub fn setup_clients( // setup all the tunnels let exit_status = KI.set_exit_wg_config( &wg_clients, - SETTING.get_exit_network().wg_tunnel_port, - &SETTING.get_exit_network().wg_private_key_path, + settings::get_rita_exit().exit_network.wg_tunnel_port, + &settings::get_rita_exit().exit_network.wg_private_key_path, ); match exit_status { @@ -425,8 +417,8 @@ pub fn enforce_exit_clients( ) -> Result, Error> { let start = Instant::now(); let mut clients_by_id = HashMap::new(); - let free_tier_limit = SETTING.get_payment().free_tier_throughput; - let close_threshold = SETTING.get_payment().close_threshold.clone(); + let free_tier_limit = settings::get_rita_exit().payment.free_tier_throughput; + let close_threshold = settings::get_rita_exit().payment.close_threshold; for client in clients_list.iter() { if let Ok(id) = to_identity(client) { clients_by_id.insert(id, client); diff --git a/rita/src/rita_exit/database/sms.rs b/rita_exit/src/database/sms.rs similarity index 95% rename from rita/src/rita_exit/database/sms.rs rename to rita_exit/src/database/sms.rs index 8f83a7300..9002eeb81 100644 --- a/rita/src/rita_exit/database/sms.rs +++ b/rita_exit/src/database/sms.rs @@ -1,9 +1,9 @@ -use crate::rita_exit::database::database_tools::text_sent; -use crate::rita_exit::database::database_tools::verify_client; -use crate::rita_exit::database::get_database_connection; -use crate::rita_exit::database::get_exit_info; -use crate::rita_exit::database::struct_tools::texts_sent; -use crate::SETTING; +use crate::database::database_tools::text_sent; +use crate::database::database_tools::verify_client; +use crate::database::get_database_connection; +use crate::database::get_exit_info; +use crate::database::struct_tools::texts_sent; + use actix_web::client as actix_client; use actix_web::client::ClientResponse; use althea_types::{ExitClientDetails, ExitClientIdentity, ExitState}; @@ -12,7 +12,7 @@ use futures01::future; use futures01::future::Either; use futures01::future::Future; use phonenumber::PhoneNumber; -use settings::exit::{ExitVerifSettings, RitaExitSettings}; +use settings::exit::ExitVerifSettings; use std::time::Duration; #[derive(Serialize)] @@ -201,8 +201,8 @@ pub struct SmsNotification { /// This function is used to send texts to the admin notification list, in the case of no configured /// admin phones you will get an empty array pub fn send_admin_notification_sms(message: &str) { - let verif_settings = SETTING.get_verif_settings(); - let exit_title = SETTING.get_description(); + let verif_settings = settings::get_rita_exit().verif_settings; + let exit_title = settings::get_rita_exit().description; if let Some(ExitVerifSettings::Phone(phone)) = verif_settings { info!("Sending Admin notification message for"); diff --git a/rita/src/rita_exit/database/struct_tools.rs b/rita_exit/src/database/struct_tools.rs similarity index 100% rename from rita/src/rita_exit/database/struct_tools.rs rename to rita_exit/src/database/struct_tools.rs diff --git a/rita_exit/src/lib.rs b/rita_exit/src/lib.rs new file mode 100644 index 000000000..e89cdfce7 --- /dev/null +++ b/rita_exit/src/lib.rs @@ -0,0 +1,98 @@ +#[macro_use] +extern crate log; + +#[macro_use] +extern crate lazy_static; + +#[macro_use] +extern crate failure; + +#[macro_use] +extern crate serde_derive; + +use althea_types::SystemChain; +use settings::exit::ExitNetworkSettings; +use settings::exit::ExitVerifSettings; + +// These are a set of vars that are never updated during runtime. This means we can have +// read only versions of them available here to prevent lock contention on large exits. +// this is probably an overengineered optimization that can be safely removed +lazy_static! { + pub static ref EXIT_WG_PRIVATE_KEY: WgKey = + settings::get_rita_exit().exit_network.wg_private_key; +} +lazy_static! { + pub static ref EXIT_VERIF_SETTINGS: Option = + settings::get_rita_exit().verif_settings; +} +// this value is actually updated so that exit prices can be changed live and we can hit the read +// only lock the vast majority of the time. +lazy_static! { + pub static ref EXIT_NETWORK_SETTINGS: ExitNetworkSettings = + settings::get_rita_exit().exit_network; +} +lazy_static! { + pub static ref EXIT_SYSTEM_CHAIN: SystemChain = settings::get_rita_exit().payment.system_chain; +} +lazy_static! { + pub static ref EXIT_DESCRIPTION: String = settings::get_rita_exit().description; +} +lazy_static! { + pub static ref EXIT_ALLOWED_COUNTRIES: HashSet = + settings::get_rita_exit().allowed_countries; +} +// price is updated at runtime, but we only want to grab a read lock to update it every few seconds +// since this is done cooperatively in get_exit_info() only one read lock is aquired but we can +// still update it every UPDATE_INTERVAL seconds +// in the format price/last updated time +lazy_static! { + pub static ref EXIT_PRICE: Arc> = Arc::new(RwLock::new(( + settings::get_rita_exit().exit_network.exit_price, + Instant::now() + ))); +} + +lazy_static! { + pub static ref DB_POOL: Arc>>> = { + let db_uri = settings::get_rita_exit().db_uri; + + if !(db_uri.contains("postgres://") + || db_uri.contains("postgresql://") + || db_uri.contains("psql://")) + { + panic!("You must provide a valid postgressql database uri!"); + } + + let manager = ConnectionManager::new(settings::get_rita_exit().db_uri); + Arc::new(RwLock::new( + r2d2::Pool::builder() + .max_size(settings::get_rita_exit().workers + 1) + .build(manager) + .expect("Failed to create pool."), + )) + }; +} + +pub mod database; +pub mod logging; +pub mod network_endpoints; +pub mod rita_loop; +pub mod traffic_watcher; + +use std::collections::HashSet; +use std::sync::Arc; +use std::sync::RwLock; +use std::time::Instant; + +use althea_types::WgKey; +use diesel::r2d2::ConnectionManager; +use diesel::r2d2::Pool; +use diesel::PgConnection; + +pub use crate::database::database_tools::*; +pub use crate::database::database_tools::*; +pub use crate::database::db_client::*; +pub use crate::database::email::*; +pub use crate::database::geoip::*; +pub use crate::database::sms::*; +pub use crate::logging::*; diff --git a/rita/src/rita_exit/mod.rs b/rita_exit/src/logging.rs similarity index 87% rename from rita/src/rita_exit/mod.rs rename to rita_exit/src/logging.rs index 6274b7ab1..92d056b77 100644 --- a/rita/src/rita_exit/mod.rs +++ b/rita_exit/src/logging.rs @@ -1,15 +1,8 @@ -pub mod database; -pub mod network_endpoints; -pub mod rita_loop; -pub mod traffic_watcher; - -use crate::SETTING; use compressed_log::builder::LoggerBuilder; use compressed_log::compression::Compression; -use failure::Error; +use failure::{bail, format_err, Error}; use log::LevelFilter; use log::Record; -use settings::RitaCommonSettings; /// enables remote logging if the user has configured it pub fn enable_remote_logging() -> Result<(), Error> { @@ -18,8 +11,8 @@ pub fn enable_remote_logging() -> Result<(), Error> { let logging_url = "https://stats.altheamesh.com:9999/compressed_sink"; let level = LevelFilter::Info; - let key = SETTING - .get_network() + let key = settings::get_rita_exit() + .network .wg_public_key .expect("Tried to init remote logging without WgKey!"); diff --git a/rita/src/rita_exit/network_endpoints/mod.rs b/rita_exit/src/network_endpoints/mod.rs similarity index 97% rename from rita/src/rita_exit/network_endpoints/mod.rs rename to rita_exit/src/network_endpoints/mod.rs index 14c0e28bb..77817b28b 100644 --- a/rita/src/rita_exit/network_endpoints/mod.rs +++ b/rita_exit/src/network_endpoints/mod.rs @@ -1,14 +1,13 @@ //! Network endpoints for rita-exit that are not dashboard or local infromational endpoints //! these are called by rita instances to operate the mesh -use crate::rita_common::debt_keeper::get_debts_list; -use crate::rita_exit::database::database_tools::get_database_connection; +use crate::database::database_tools::get_database_connection; +use crate::database::{client_status, get_exit_info, signup_client}; #[cfg(feature = "development")] use crate::rita_exit::database::db_client::DbClient; #[cfg(feature = "development")] use crate::rita_exit::database::db_client::TruncateTables; -use crate::rita_exit::database::{client_status, get_exit_info, signup_client}; -use crate::EXIT_WG_PRIVATE_KEY; + #[cfg(feature = "development")] use actix::SystemService; #[cfg(feature = "development")] @@ -19,16 +18,19 @@ use althea_types::WgKey; use althea_types::{ EncryptedExitClientIdentity, EncryptedExitState, ExitClientIdentity, ExitState, }; -use failure::Error; +use failure::{format_err, Error}; use futures01::future; use futures01::Future; use num256::Int256; +use rita_common::debt_keeper::get_debts_list; use sodiumoxide::crypto::box_; use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305::Nonce; use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305::PublicKey; use sodiumoxide::crypto::box_::curve25519xsalsa20poly1305::SecretKey; use std::net::SocketAddr; +use crate::EXIT_WG_PRIVATE_KEY; + /// helper function for returning from secure_setup_request() fn secure_setup_return( ret: ExitState, diff --git a/rita/src/rita_exit/rita_loop/mod.rs b/rita_exit/src/rita_loop/mod.rs similarity index 90% rename from rita/src/rita_exit/rita_loop/mod.rs rename to rita_exit/src/rita_loop/mod.rs index 17f6a009c..bf073abd8 100644 --- a/rita/src/rita_exit/rita_loop/mod.rs +++ b/rita_exit/src/rita_loop/mod.rs @@ -10,18 +10,14 @@ //! Two threads are generated by this, one actual worker thread and a watchdog restarting thread that only //! wakes up to restart the inner thread if anything goes wrong. -use crate::rita_common::debt_keeper::DebtAction; -use crate::rita_common::utils::wait_timeout::wait_timeout; -use crate::rita_common::utils::wait_timeout::WaitResult; -use crate::rita_exit::database::database_tools::get_database_connection_sync; -use crate::rita_exit::database::struct_tools::clients_to_ids; -use crate::rita_exit::database::{ +use crate::network_endpoints::*; + +use crate::database::database_tools::get_database_connection_sync; +use crate::database::struct_tools::clients_to_ids; +use crate::database::{ cleanup_exit_clients, enforce_exit_clients, setup_clients, validate_clients_region, }; -use crate::rita_exit::network_endpoints::*; -use crate::rita_exit::traffic_watcher::{TrafficWatcher, Watch}; -use crate::KI; -use crate::SETTING; +use crate::traffic_watcher::{TrafficWatcher, Watch}; use actix::Addr; use actix::System; use actix::SystemService; @@ -35,13 +31,16 @@ use babel_monitor_legacy::start_connection_legacy; use diesel::{query_dsl::RunQueryDsl, PgConnection}; use exit_db::models; use futures01::future::Future; -use settings::exit::RitaExitSettings; -use settings::RitaCommonSettings; +use rita_common::debt_keeper::DebtAction; +use rita_common::utils::wait_timeout::wait_timeout; +use rita_common::utils::wait_timeout::WaitResult; use std::collections::HashSet; use std::thread; use std::time::Duration; use std::time::Instant; +use rita_common::KI; + // the speed in seconds for the exit loop pub const EXIT_LOOP_SPEED: u64 = 5; pub const EXIT_LOOP_SPEED_DURATION: Duration = Duration::from_secs(EXIT_LOOP_SPEED); @@ -115,7 +114,7 @@ fn rita_exit_loop( match get_database_connection_sync() { Ok(conn) => { use exit_db::schema::clients::dsl::clients; - let babel_port = SETTING.get_network().babel_port; + let babel_port = settings::get_rita_exit().network.babel_port; info!( "Exit tick! got DB connection after {}ms", start.elapsed().as_millis(), @@ -166,7 +165,7 @@ fn rita_exit_loop( Err(e) => { error!("Failed to get database connection with {}", e); if !*successful_setup { - let db_uri = SETTING.get_db_uri(); + let db_uri = settings::get_rita_exit().db_uri; let message = format!( "Failed to get database connection to {} on first setup loop, the exit can not operate without the ability to get the clients list from the database exiting", db_uri @@ -222,7 +221,7 @@ fn bill(babel_port: u16, tw: &Addr, start: Instant, ids: Vec, conn: &PgConnection) { - let val = SETTING.get_allowed_countries().is_empty(); + let val = settings::get_rita_exit().allowed_countries.is_empty(); if !val { let res = validate_clients_region(clients_list, &conn); match res { @@ -244,17 +243,20 @@ fn setup_exit_wg_tunnel() { warn!("exit setup returned {}", e) } KI.one_time_exit_setup( - &SETTING.get_exit_network().own_internal_ip.into(), - SETTING.get_exit_network().netmask, + &settings::get_rita_exit() + .exit_network + .own_internal_ip + .into(), + settings::get_rita_exit().exit_network.netmask, ) .expect("Failed to setup wg_exit!"); - KI.setup_nat(&SETTING.get_network().external_nic.clone().unwrap()) + KI.setup_nat(&settings::get_rita_exit().network.external_nic.unwrap()) .unwrap(); } pub fn check_rita_exit_actors() { - assert!(crate::rita_exit::traffic_watcher::TrafficWatcher::from_registry().connected()); - assert!(crate::rita_exit::database::db_client::DbClient::from_registry().connected()); + assert!(crate::traffic_watcher::TrafficWatcher::from_registry().connected()); + assert!(crate::database::db_client::DbClient::from_registry().connected()); } pub fn start_rita_exit_endpoints(workers: usize) { @@ -277,7 +279,7 @@ pub fn start_rita_exit_endpoints(workers: usize) { .workers(workers) .bind(format!( "[::0]:{}", - SETTING.get_exit_network().exit_hello_port + settings::get_rita_exit().exit_network.exit_hello_port )) .unwrap() .shutdown_timeout(0) diff --git a/rita/src/rita_exit/traffic_watcher/mod.rs b/rita_exit/src/traffic_watcher/mod.rs similarity index 94% rename from rita/src/rita_exit/traffic_watcher/mod.rs rename to rita_exit/src/traffic_watcher/mod.rs index 28ecc1d35..dcf77a285 100644 --- a/rita/src/rita_exit/traffic_watcher/mod.rs +++ b/rita_exit/src/traffic_watcher/mod.rs @@ -8,12 +8,13 @@ //! //! Also handles enforcement of nonpayment, since there's no need for a complicated TunnelManager for exits -use crate::rita_common::debt_keeper::traffic_update; -use crate::rita_common::debt_keeper::Traffic; -use crate::rita_common::usage_tracker::update_usage_data; -use crate::rita_common::usage_tracker::UpdateUsage; -use crate::rita_common::usage_tracker::UsageType; -use crate::SETTING; +use failure::bail; +use rita_common::debt_keeper::traffic_update; +use rita_common::debt_keeper::Traffic; +use rita_common::usage_tracker::update_usage_data; +use rita_common::usage_tracker::UpdateUsage; +use rita_common::usage_tracker::UsageType; + use actix::{Actor, Context, Handler, Message, Supervised, SystemService}; use althea_kernel_interface::wg_iface_counter::prepare_usage_history; use althea_kernel_interface::wg_iface_counter::WgUsage; @@ -23,11 +24,8 @@ use althea_types::WgKey; use babel_monitor::Route as RouteLegacy; use failure::Error; use ipnetwork::IpNetwork; -use settings::exit::RitaExitSettings; -use settings::RitaCommonSettings; use std::collections::HashMap; use std::net::IpAddr; - pub struct TrafficWatcher { last_seen_bytes: HashMap, } @@ -74,13 +72,13 @@ fn get_babel_info( ) -> HashMap { // we assume this matches what is actually set it babel becuase we // panic on startup if it does not get set correctly - let local_fee = SETTING.get_payment().local_fee; + let local_fee = settings::get_rita_exit().payment.local_fee; // insert ourselves as a destination, don't think this is actually needed let mut destinations = HashMap::new(); destinations.insert(our_id.wg_public_key, u64::from(local_fee)); - let max_fee = SETTING.get_payment().max_fee; + let max_fee = settings::get_rita_exit().payment.max_fee; for route in routes { // Only ip6 if let IpNetwork::V6(ref ip) = route.prefix { @@ -112,7 +110,8 @@ struct HelperMapReturn { fn generate_helper_maps(our_id: &Identity, clients: &[Identity]) -> HelperMapReturn { let mut identities: HashMap = HashMap::new(); let mut id_from_ip: HashMap = HashMap::new(); - let our_settings = SETTING.get_network(); + let rita_exit = settings::get_rita_exit(); + let our_settings = rita_exit.network; id_from_ip.insert(our_settings.mesh_ip.unwrap(), *our_id); for ident in clients.iter() { @@ -189,8 +188,8 @@ pub fn watch( routes: &[RouteLegacy], clients: &[Identity], ) -> Result<(), Error> { - let our_price = SETTING.get_exit_network().exit_price; - let our_id = match SETTING.get_identity() { + let our_price = settings::get_rita_exit().exit_network.exit_price; + let our_id = match settings::get_rita_exit().get_identity() { Some(id) => id, None => { warn!("Our identity is not ready!"); diff --git a/rita_tower/Cargo.toml b/rita_tower/Cargo.toml new file mode 100644 index 000000000..796f26a88 --- /dev/null +++ b/rita_tower/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "rita_tower" +version = "0.18.0" +edition = "2018" +license = "Apache-2.0" + +[dependencies] +althea_types = { path = "../althea_types"} +lazy_static = "1.4" +serde_derive = "1.0" +serde = "1.0" +serde_json = "1.0" +log = { version = "0.4", features = ["release_max_level_info"] } diff --git a/rita_tower/src/errors.rs b/rita_tower/src/errors.rs new file mode 100644 index 000000000..a13c9c1a4 --- /dev/null +++ b/rita_tower/src/errors.rs @@ -0,0 +1,215 @@ +use std::{env, fmt}; +use std::{ + error::Error, + time::{Instant, SystemTimeError}, +}; +use std::{io::ErrorKind, num::ParseIntError}; +use std::{ + num::ParseFloatError, + process::{Command, Output}, +}; +use std::{ + str::Utf8Error, + sync::{Arc, Mutex}, +}; + +use std::str; + +use althea_types::error::AltheaTypesError; + +use std::fmt::Result as FormatResult; +use std::io::Error as IoError; +use std::net::AddrParseError; +use std::string::FromUtf8Error; + +type CommandFunction = Box) -> Result + Send>; + +#[derive(Clone, Debug)] +pub enum TowerError { + RuntimeError(String), + FailedToGetEnbsError, + FailedToGetConnectedUesError, + FailedToGetAttachedUesError, + FailedToGetUptime, +} + +impl fmt::Display for TowerError { + fn fmt(&self, f: &mut fmt::Formatter) -> FormatResult { + match self { + TowerError::RuntimeError(val) => write!(f, "Runtime Error: {}", val), + + TowerError::FailedToGetEnbsError => write!(f, "Unable to handle or obtain enbs file"), + TowerError::FailedToGetConnectedUesError => { + write!(f, "Unable to handle or obtain connected ues file") + } + TowerError::FailedToGetAttachedUesError => { + write!(f, "Unable to handle or obtain attached ues file") + } + TowerError::FailedToGetUptime => { + write!(f, "Unable to parse string for uptime") + } + } + } +} + +impl Error for TowerError {} + +impl From for TowerError { + fn from(e: FromUtf8Error) -> Self { + TowerError::RuntimeError(format!("{}", e)) + } +} + +impl From for TowerError { + fn from(e: IoError) -> Self { + TowerError::RuntimeError(format!("{}", e)) + } +} + +impl From for TowerError { + fn from(e: AddrParseError) -> Self { + TowerError::RuntimeError(format!("{}", e)) + } +} + +impl From for TowerError { + fn from(e: ParseIntError) -> Self { + TowerError::RuntimeError(format!("{}", e)) + } +} + +impl From for TowerError { + fn from(e: ParseFloatError) -> Self { + TowerError::RuntimeError(format!("{}", e)) + } +} + +impl From for TowerError { + fn from(e: AltheaTypesError) -> Self { + TowerError::RuntimeError(format!("{}", e)) + } +} + +impl From for TowerError { + fn from(e: Utf8Error) -> Self { + TowerError::RuntimeError(format!("{}", e)) + } +} + +impl From for TowerError { + fn from(e: SystemTimeError) -> Self { + TowerError::RuntimeError(format!("{}", e)) + } +} + +#[cfg(test)] +lazy_static! { + pub static ref KI: Box = Box::new(TestCommandRunner { + run_command: Arc::new(Mutex::new(Box::new(|_program, _args| { + panic!("kernel interface used before initialized"); + }))) + }); +} + +#[cfg(not(test))] +lazy_static! { + pub static ref KI: Box = Box::new(LinuxCommandRunner {}); +} + +pub trait CommandRunner { + fn run_command(&self, program: &str, args: &[&str]) -> Result; + fn set_mock(&self, mock: CommandFunction); +} + +// a quick throwaway function to print arguments arrays so that they can be copy/pasted from logs +fn print_str_array(input: &[&str]) -> String { + let mut output = String::new(); + for item in input { + output = output + " " + item; + } + output +} + +pub struct LinuxCommandRunner; + +impl CommandRunner for LinuxCommandRunner { + fn run_command(&self, program: &str, args: &[&str]) -> Result { + let start = Instant::now(); + let output = match Command::new(program).args(args).output() { + Ok(o) => o, + Err(e) => { + if e.kind() == ErrorKind::NotFound { + error!("The {:?} binary was not found. Please install a package that provides it. PATH={:?}", program, env::var("PATH")); + } + return Err(e.into()); + } + }; + + trace!( + "Command {} {} returned: {:?}", + program, + print_str_array(args), + output + ); + if !output.status.success() { + trace!( + "Command {} {} returned: an error {:?}", + program, + print_str_array(args), + output + ); + } + trace!( + "command completed in {}s {}ms", + start.elapsed().as_secs(), + start.elapsed().subsec_millis() + ); + + if start.elapsed().as_secs() > 5 { + error!( + "Command {} {} took more than five seconds to complete!", + program, + print_str_array(args) + ); + } else if start.elapsed().as_secs() > 1 { + warn!( + "Command {} {} took more than one second to complete!", + program, + print_str_array(args) + ); + } + + Ok(output) + } + + fn set_mock( + &self, + _mock: Box) -> Result + Send>, + ) { + unimplemented!() + } +} + +pub struct TestCommandRunner { + pub run_command: Arc>, +} + +impl CommandRunner for TestCommandRunner { + fn run_command(&self, program: &str, args: &[&str]) -> Result { + let mut args_owned = Vec::new(); + for a in args { + args_owned.push((*a).to_string()) + } + + (&mut *self.run_command.lock().unwrap())(program.to_string(), args_owned) + } + + fn set_mock(&self, mock: CommandFunction) { + *self.run_command.lock().unwrap() = mock + } +} + +pub trait Tower: CommandRunner + Sync + Send {} + +impl Tower for LinuxCommandRunner {} +impl Tower for TestCommandRunner {} diff --git a/rita_tower/src/lib.rs b/rita_tower/src/lib.rs new file mode 100644 index 000000000..8c8805fce --- /dev/null +++ b/rita_tower/src/lib.rs @@ -0,0 +1,12 @@ +#[macro_use] +extern crate lazy_static; + +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate log; + +pub mod errors; +pub mod structs; +// pub mod tower_info; diff --git a/rita_tower/src/structs.rs b/rita_tower/src/structs.rs new file mode 100644 index 000000000..74ae2f622 --- /dev/null +++ b/rita_tower/src/structs.rs @@ -0,0 +1,22 @@ +use std::time::Duration; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum RoleSpecificCheckin { + RitaTower, +} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RitaTowerInfo { + pub connected_enbs: f32, + pub connected_ues: f32, + pub attached_ues: f32, + #[serde(default)] + pub mme_start_time: Duration, + #[serde(default)] + pub sgwc_start_time: Duration, + #[serde(default)] + pub sgwu_start_time: Duration, + #[serde(default)] + pub smf_start_time: Duration, + #[serde(default)] + pub upf_start_time: Duration, +} diff --git a/rita_tower/src/tower_info.rs b/rita_tower/src/tower_info.rs new file mode 100644 index 000000000..fd7edfc34 --- /dev/null +++ b/rita_tower/src/tower_info.rs @@ -0,0 +1,209 @@ +// use crate::errors::TowerError as Error; +// use crate::structs::RitaTowerInfo; + +// use std::fs::File; +// use std::io::BufRead; +// use std::io::BufReader; +// use std::time::Duration; +// use std::u64; + +// fn get_rita_tower_info() -> Result { +// let connected_enbs = parse_connected_enbs()?; +// let connected_ues = parse_connected_ues()?; +// let attached_ues = parse_attached_ues()?; +// let mme_start_time = get_mme_start_time()?; +// let sgwc_start_time = get_sgwc_start_time()?; +// let sgwu_start_time = get_sgwu_start_time()?; +// let smf_start_time = get_smf_start_time()?; +// let upf_start_time = get_upf_start_time()?; + +// Ok(RitaTowerInfo { +// connected_enbs, +// connected_ues, +// attached_ues, +// mme_start_time, +// sgwc_start_time, +// sgwu_start_time, +// smf_start_time, +// upf_start_time, +// }) +// } + +// fn parse_connected_enbs() -> Result { +// let connected_enbs_error = Err(Error::FailedToGetEnbsError); + +// let lines = get_lines("/tmp/open5gs/connected_enbs")?; +// let line = match lines.get(0) { +// Some(line) => line, +// None => return connected_enbs_error, +// }; + +// let mut iter = line.split_whitespace(); +// let connected_enbs: f32 = match iter.next() { +// Some(val) => val.parse()?, +// None => return connected_enbs_error, +// }; + +// Ok(connected_enbs) +// } +// fn parse_connected_ues() -> Result { +// let connected_ues_error = Err(Error::FailedToGetConnectedUesError); + +// let lines = get_lines("/tmp/open5gs/connected_ues")?; +// let line = match lines.get(0) { +// Some(line) => line, +// None => return connected_ues_error, +// }; + +// let mut iter = line.split_whitespace(); +// let connected_ues: f32 = match iter.next() { +// Some(val) => val.parse()?, +// None => return connected_ues_error, +// }; + +// Ok(connected_ues) +// } +// fn parse_attached_ues() -> Result { +// let attached_ues_error = Err(Error::FailedToGetAttachedUesError); + +// let lines = get_lines("/tmp/open5gs/attached_ues")?; +// let line = match lines.get(0) { +// Some(line) => line, +// None => return attached_ues_error, +// }; + +// let mut iter = line.split_whitespace(); +// let attached_ues: f32 = match iter.next() { +// Some(val) => val.parse()?, +// None => return attached_ues_error, +// }; + +// Ok(attached_ues) +// } + +// fn parse_uptime(lines: Vec) -> Result { +// let uptime_error = Err(Error::FailedToGetUptime); + +// let line = match lines.get(1) { +// Some(line) => line, +// None => return uptime_error, +// }; + +// let mut iter = line.split_whitespace(); + +// let uptime: u64 = match iter.next() { +// Some(val) => val.parse()?, +// None => return uptime_error, +// }; + +// Ok(Duration::new(uptime, 0)) +// } + +// fn get_mme_start_time() -> Result { +// let lines = get_lines("/tmp/open5gs/mme_start_time")?; + +// let mme_start_time = parse_uptime(lines)?; + +// Ok(mme_start_time) +// } +// fn get_sgwc_start_time() -> Result { +// let lines = get_lines("/tmp/open5gs/sgwc_start_time")?; + +// let sgwc_start_time = parse_uptime(lines)?; + +// Ok(sgwc_start_time) +// } +// fn get_sgwu_start_time() -> Result { +// let lines = get_lines("/tmp/open5gs/sgwu_start_time")?; + +// let sgwu_start_time = parse_uptime(lines)?; + +// Ok(sgwu_start_time) +// } +// fn get_smf_start_time() -> Result { +// let lines = get_lines("/tmp/open5gs/smf_start_time")?; + +// let smf_start_time = parse_uptime(lines)?; + +// Ok(smf_start_time) +// } +// fn get_upf_start_time() -> Result { +// let lines = get_lines("/tmp/open5gs/upf_start_time")?; + +// let upf_start_time = parse_uptime(lines)?; + +// Ok(upf_start_time) +// } + +// pub fn get_lines(filename: &str) -> Result, Error> { +// let f = File::open(filename)?; +// let file = BufReader::new(&f); +// let mut out_lines = Vec::new(); +// for line in file.lines() { +// match line { +// Ok(val) => out_lines.push(val), +// Err(_) => break, +// } +// } + +// Ok(out_lines) +// } +// // Test for rita_tower +// #[cfg(test)] +// mod test { +// use crate::tower_info::{ +// get_mme_start_time, get_sgwc_start_time, get_sgwu_start_time, get_smf_start_time, +// get_upf_start_time, parse_attached_ues, parse_connected_enbs, parse_connected_ues, +// }; + +// //use super::get_rita_tower_info; +// // #[test] +// // fn test_get_rita_tower_info() { +// // let res = get_rita_tower_info(); +// // println!("{:?}", res) +// // } +// #[test] +// fn test_parse_connected_enbs() { +// let res = parse_connected_enbs(); +// println!("{:?}", res) +// } +// #[test] +// fn test_connected_ues() { +// let res = parse_connected_ues(); +// println!("{:?}", res) +// } +// #[test] +// fn test_attached_ues() { +// let res = parse_attached_ues(); +// println!("{:?}", res) +// } + +// #[test] +// fn test_all_uptime() { +// test_mme_start_time(); +// test_sgwc_start_time(); +// test_sgwu_start_time(); +// test_smf_start_time(); +// test_upf_start_time(); +// } +// fn test_mme_start_time() { +// let res = get_mme_start_time().unwrap(); +// println!("{:?}", res.as_secs()); +// } +// fn test_sgwc_start_time() { +// let res = get_sgwc_start_time().unwrap(); +// println!("{:?}", res.as_secs()); +// } +// fn test_sgwu_start_time() { +// let res = get_sgwu_start_time().unwrap(); +// println!("{:?}", res.as_secs()); +// } +// fn test_smf_start_time() { +// let res = get_smf_start_time().unwrap(); +// println!("{:?}", res.as_secs()); +// } +// fn test_upf_start_time() { +// let res = get_upf_start_time().unwrap(); +// println!("{:?}", res.as_secs()); +// } +// } diff --git a/scripts/test.sh b/scripts/test.sh index d6275b763..4c1e29510 100644 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -10,7 +10,7 @@ cargo clippy --all --all-targets --all-features -- -D warnings cargo fmt --all -- --check # test rita only on many architectures -CROSS_TEST_ARGS="--verbose -p rita --bin rita --features bundle_openssl -- --test-threads=1" +CROSS_TEST_ARGS="--verbose -p rita_bin --bin rita --features bundle_openssl -- --test-threads=1" cross test --target x86_64-unknown-linux-musl $CROSS_TEST_ARGS cross test --target mips-unknown-linux-gnu $CROSS_TEST_ARGS cross test --target mipsel-unknown-linux-gnu $CROSS_TEST_ARGS diff --git a/settings/Cargo.toml b/settings/Cargo.toml index 877a556e7..0d64075c2 100644 --- a/settings/Cargo.toml +++ b/settings/Cargo.toml @@ -20,4 +20,4 @@ owning_ref = "0.4" lazy_static = "1.4" clarity = "0.4" arrayvec = {version= "0.7", features = ["serde"]} -phonenumber = "0.3" +phonenumber = "0.3" \ No newline at end of file diff --git a/settings/src/client.rs b/settings/src/client.rs index e69523b76..aa7cb7a53 100644 --- a/settings/src/client.rs +++ b/settings/src/client.rs @@ -1,17 +1,13 @@ -use crate::json_merge; use crate::localization::LocalizationSettings; use crate::logging::LoggingSettings; use crate::network::NetworkSettings; use crate::operator::OperatorSettings; use crate::payment::PaymentSettings; -use crate::spawn_watch_thread; -use crate::RitaCommonSettings; +use crate::{json_merge, set_rita_client, spawn_watch_thread_client}; use althea_types::{ContactStorage, ExitState, Identity}; use config::Config; use failure::Error; -use owning_ref::{RwLockReadGuardRef, RwLockWriteGuardRefMut}; use std::collections::{HashMap, HashSet}; -use std::sync::{Arc, RwLock}; /// This struct is used by rita to store exit specific information /// There is one instance per exit @@ -73,83 +69,7 @@ impl ExitClientSettings { } } -pub trait RitaClientSettings { - fn get_exit_client<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaSettingsStruct, ExitClientSettings>; - fn get_exit_client_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaSettingsStruct, ExitClientSettings>; - fn get_exits<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaSettingsStruct, HashMap>; - fn get_exits_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaSettingsStruct, HashMap>; - fn get_log<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaSettingsStruct, LoggingSettings>; - fn get_log_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaSettingsStruct, LoggingSettings>; - fn get_operator<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaSettingsStruct, OperatorSettings>; - fn get_operator_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaSettingsStruct, OperatorSettings>; -} - -impl RitaClientSettings for Arc> { - fn get_exit_client<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaSettingsStruct, ExitClientSettings> { - RwLockReadGuardRef::new(self.read().unwrap()).map(|g| &g.exit_client) - } - fn get_exit_client_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaSettingsStruct, ExitClientSettings> { - RwLockWriteGuardRefMut::new(self.write().unwrap()).map_mut(|g| &mut g.exit_client) - } - - fn get_exits<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaSettingsStruct, HashMap> { - RwLockReadGuardRef::new(self.read().unwrap()).map(|g| &g.exit_client.exits) - } - - fn get_exits_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaSettingsStruct, HashMap> { - RwLockWriteGuardRefMut::new(self.write().unwrap()).map_mut(|g| &mut g.exit_client.exits) - } - - fn get_log<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaSettingsStruct, LoggingSettings> { - RwLockReadGuardRef::new(self.read().unwrap()).map(|g| &g.log) - } - - fn get_log_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaSettingsStruct, LoggingSettings> { - RwLockWriteGuardRefMut::new(self.write().unwrap()).map_mut(|g| &mut g.log) - } - - fn get_operator<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaSettingsStruct, OperatorSettings> { - RwLockReadGuardRef::new(self.read().unwrap()).map(|g| &g.operator) - } - - fn get_operator_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaSettingsStruct, OperatorSettings> { - RwLockWriteGuardRefMut::new(self.write().unwrap()).map_mut(|g| &mut g.operator) - } -} - -impl RitaSettingsStruct { +impl RitaClientSettings { pub fn new(file_name: &str) -> Result { let mut s = Config::new(); s.merge(config::File::with_name(file_name).required(false))?; @@ -158,16 +78,14 @@ impl RitaSettingsStruct { Ok(settings) } - pub fn new_watched(file_name: &str) -> Result>, Error> { + pub fn new_watched(file_name: &str) -> Result { let mut s = Config::new(); s.merge(config::File::with_name(file_name).required(false))?; let settings: Self = s.try_into()?; - let settings = Arc::new(RwLock::new(settings)); - - trace!("starting with settings: {:?}", settings.read().unwrap()); + set_rita_client(settings.clone()); - spawn_watch_thread(settings.clone(), file_name); + spawn_watch_thread_client(settings.clone(), file_name); Ok(settings) } @@ -179,76 +97,52 @@ impl RitaSettingsStruct { /// This is the main struct for rita #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Default)] -pub struct RitaSettingsStruct { - payment: PaymentSettings, +pub struct RitaClientSettings { + pub payment: PaymentSettings, #[serde(default)] - log: LoggingSettings, + pub log: LoggingSettings, #[serde(default)] - operator: OperatorSettings, + pub operator: OperatorSettings, #[serde(default)] - localization: LocalizationSettings, - network: NetworkSettings, - exit_client: ExitClientSettings, + pub localization: LocalizationSettings, + pub network: NetworkSettings, + pub exit_client: ExitClientSettings, #[serde(skip)] - future: bool, + pub future: bool, } -impl RitaCommonSettings for Arc> { - fn get_payment<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaSettingsStruct, PaymentSettings> { - RwLockReadGuardRef::new(self.read().unwrap()).map(|g| &g.payment) - } - - fn get_payment_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaSettingsStruct, PaymentSettings> { - RwLockWriteGuardRefMut::new(self.write().unwrap()).map_mut(|g| &mut g.payment) - } - - fn get_localization<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaSettingsStruct, LocalizationSettings> { - RwLockReadGuardRef::new(self.read().unwrap()).map(|g| &g.localization) - } - - fn get_localization_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaSettingsStruct, LocalizationSettings> { - RwLockWriteGuardRefMut::new(self.write().unwrap()).map_mut(|g| &mut g.localization) +impl RitaClientSettings { + pub fn get_payment(&self) -> PaymentSettings { + self.payment.clone() } - fn get_network<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaSettingsStruct, NetworkSettings> { - RwLockReadGuardRef::new(self.read().unwrap()).map(|g| &g.network) + pub fn get_localization(&self) -> LocalizationSettings { + self.localization.clone() } - fn get_network_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaSettingsStruct, NetworkSettings> { - RwLockWriteGuardRefMut::new(self.write().unwrap()).map_mut(|g| &mut g.network) + pub fn get_network(&self) -> NetworkSettings { + self.network.clone() } - fn merge(&self, changed_settings: serde_json::Value) -> Result<(), Error> { - let mut settings_value = serde_json::to_value(self.read().unwrap().clone())?; + pub fn merge(&mut self, changed_settings: serde_json::Value) -> Result<(), Error> { + let mut settings_value = serde_json::to_value(self.clone())?; json_merge(&mut settings_value, &changed_settings); match serde_json::from_value(settings_value) { Ok(new_settings) => { - *self.write().unwrap() = new_settings; + *self = new_settings; Ok(()) } Err(e) => Err(e.into()), } } - fn get_all(&self) -> Result { - Ok(serde_json::to_value(self.read().unwrap().clone())?) + pub fn get_all(&self) -> Result { + Ok(serde_json::to_value(self.clone())?) } - fn get_identity(&self) -> Option { + pub fn get_identity(&self) -> Option { Some(Identity::new( self.get_network().mesh_ip?, self.get_payment().eth_address?, @@ -257,11 +151,11 @@ impl RitaCommonSettings for Arc> )) } - fn get_future(&self) -> bool { - self.read().unwrap().future + pub fn get_future(&self) -> bool { + self.future } - fn set_future(&self, future: bool) { - self.write().unwrap().future = future + pub fn set_future(&mut self, future: bool) { + self.future = future } } diff --git a/settings/src/exit.rs b/settings/src/exit.rs index 6609fd80a..b3953017a 100644 --- a/settings/src/exit.rs +++ b/settings/src/exit.rs @@ -1,19 +1,14 @@ -use crate::json_merge; use crate::localization::LocalizationSettings; use crate::network::NetworkSettings; use crate::payment::PaymentSettings; -use crate::spawn_watch_thread; -use crate::RitaCommonSettings; -use althea_types::Identity; -use althea_types::WgKey; +use crate::{json_merge, set_rita_exit, spawn_watch_thread_exit}; +use althea_types::{Identity, WgKey}; use config::Config; use core::str::FromStr; use failure::Error; -use owning_ref::{RwLockReadGuardRef, RwLockWriteGuardRefMut}; use phonenumber::PhoneNumber; use std::collections::HashSet; use std::net::Ipv4Addr; -use std::sync::{Arc, RwLock}; /// This is the network settings specific to rita_exit #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] @@ -166,27 +161,27 @@ pub enum ExitVerifSettings { #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct RitaExitSettingsStruct { /// starts with file:// or postgres://username:password@localhost/diesel_demo - db_uri: String, + pub db_uri: String, /// the size of the worker thread pool, the connection pool is this plus one - workers: u32, + pub workers: u32, /// if we should log remotely or if we should send our logs to the logging server #[serde(default = "default_remote_log")] - remote_log: bool, + pub remote_log: bool, /// The description of this exit, what is sent to clients and displayed to the user - description: String, - payment: PaymentSettings, + pub description: String, + pub payment: PaymentSettings, #[serde(default)] - localization: LocalizationSettings, - network: NetworkSettings, - exit_network: ExitNetworkSettings, + pub localization: LocalizationSettings, + pub network: NetworkSettings, + pub exit_network: ExitNetworkSettings, /// Countries which the clients to the exit are allowed from, blank for no geoip validation. /// (ISO country code) #[serde(skip_serializing_if = "HashSet::is_empty", default)] - allowed_countries: HashSet, + pub allowed_countries: HashSet, #[serde(skip_serializing_if = "Option::is_none")] - verif_settings: Option, + pub verif_settings: Option, #[serde(skip)] - future: bool, + pub future: bool, } impl RitaExitSettingsStruct { @@ -207,158 +202,56 @@ impl RitaExitSettingsStruct { future: false, } } -} - -pub trait RitaExitSettings { - fn get_exit_network<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaExitSettingsStruct, ExitNetworkSettings>; - fn get_verif_settings(&self) -> Option; - fn get_verif_settings_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaExitSettingsStruct, Option>; - fn get_db_uri(&self) -> String; - fn get_remote_log(&self) -> bool; - fn get_workers(&self) -> u32; - fn get_description(&self) -> String; - fn get_allowed_countries<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaExitSettingsStruct, HashSet>; -} - -impl RitaExitSettings for Arc> { - fn get_exit_network<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaExitSettingsStruct, ExitNetworkSettings> { - RwLockReadGuardRef::new(self.read().unwrap()).map(|g| &g.exit_network) - } - fn get_db_uri(&self) -> String { - self.read().unwrap().db_uri.clone() - } - fn get_remote_log(&self) -> bool { - self.read().unwrap().remote_log - } - fn get_workers(&self) -> u32 { - self.read().unwrap().workers - } - fn get_description(&self) -> String { - self.read().unwrap().description.clone() - } - fn get_allowed_countries<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaExitSettingsStruct, HashSet> { - RwLockReadGuardRef::new(self.read().unwrap()).map(|g| &g.allowed_countries) - } - fn get_verif_settings(&self) -> Option { - self.read().unwrap().verif_settings.clone() - } - fn get_verif_settings_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaExitSettingsStruct, Option> { - RwLockWriteGuardRefMut::new(self.write().unwrap()).map_mut(|g| &mut g.verif_settings) - } -} - -impl RitaExitSettingsStruct { - pub fn new(file_name: &str) -> Result { - let mut s = Config::new(); - s.merge(config::File::with_name(file_name).required(false))?; - let settings: Self = s.try_into()?; - Ok(settings) - } - - pub fn new_watched(file_name: &str) -> Result>, Error> { - let mut s = Config::new(); - s.merge(config::File::with_name(file_name).required(false))?; - let settings: Self = s.try_into()?; - - let settings = Arc::new(RwLock::new(settings)); - - trace!("starting with settings: {:?}", settings.read().unwrap()); - - spawn_watch_thread(settings.clone(), file_name); - - Ok(settings) - } -} - -impl RitaCommonSettings for Arc> { - fn get_payment<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaExitSettingsStruct, PaymentSettings> { - RwLockReadGuardRef::new(self.read().expect("Read payment settings!")).map(|g| &g.payment) - } - - fn get_payment_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaExitSettingsStruct, PaymentSettings> { - RwLockWriteGuardRefMut::new(self.write().expect("Failed to write payment settings!")) - .map_mut(|g| &mut g.payment) - } - - fn get_localization_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaExitSettingsStruct, LocalizationSettings> { - RwLockWriteGuardRefMut::new( - self.write() - .expect("Failed to write localization settings!"), - ) - .map_mut(|g| &mut g.localization) + pub fn get_network(&self) -> NetworkSettings { + self.network.clone() } - - fn get_localization<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaExitSettingsStruct, LocalizationSettings> { - RwLockReadGuardRef::new(self.read().expect("Failed to read localization settings!")) - .map(|g| &g.localization) + pub fn get_payment(&self) -> PaymentSettings { + self.payment.clone() } - fn get_network<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, RitaExitSettingsStruct, NetworkSettings> { - RwLockReadGuardRef::new(self.read().expect("Failed to read network settings!")) - .map(|g| &g.network) + pub fn get_identity(&self) -> Option { + Some(Identity::new( + self.network.mesh_ip?, + self.payment.eth_address?, + self.network.wg_public_key?, + self.network.nickname, + )) } - fn get_network_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, RitaExitSettingsStruct, NetworkSettings> { - RwLockWriteGuardRefMut::new(self.write().expect("Failed to write network settings!")) - .map_mut(|g| &mut g.network) + pub fn get_all(&self) -> Result { + Ok(serde_json::to_value(self.clone())?) } - fn merge(&self, changed_settings: serde_json::Value) -> Result<(), Error> { - let mut settings_value = serde_json::to_value(self.read().unwrap().clone())?; + pub fn merge(&mut self, changed_settings: serde_json::Value) -> Result<(), Error> { + let mut settings_value = serde_json::to_value(self.clone())?; json_merge(&mut settings_value, &changed_settings); match serde_json::from_value(settings_value) { Ok(new_settings) => { - *self.write().unwrap() = new_settings; + *self = new_settings; Ok(()) } Err(e) => Err(e.into()), } } - fn get_all(&self) -> Result { - Ok(serde_json::to_value(self.read().unwrap().clone())?) + pub fn new(file_name: &str) -> Result { + let mut s = Config::new(); + s.merge(config::File::with_name(file_name).required(false))?; + let settings: Self = s.try_into()?; + Ok(settings) } - fn get_identity(&self) -> Option { - Some(Identity::new( - self.get_network().mesh_ip?, - self.get_payment().eth_address?, - self.get_network().wg_public_key?, - self.get_network().nickname, - )) - } + pub fn new_watched(file_name: &str) -> Result { + let mut s = Config::new(); + s.merge(config::File::with_name(file_name).required(false))?; + let settings: Self = s.try_into()?; - fn get_future(&self) -> bool { - self.read().unwrap().future - } + set_rita_exit(settings.clone()); + + spawn_watch_thread_exit(settings.clone(), file_name); - fn set_future(&self, future: bool) { - self.write().unwrap().future = future + Ok(settings) } } diff --git a/settings/src/lib.rs b/settings/src/lib.rs index 9f02c2d4c..63d0e71be 100644 --- a/settings/src/lib.rs +++ b/settings/src/lib.rs @@ -17,23 +17,14 @@ extern crate serde_derive; extern crate log; extern crate arrayvec; -use crate::localization::LocalizationSettings; -use crate::network::NetworkSettings; -use crate::payment::PaymentSettings; -use althea_kernel_interface::KernelInterface; -#[cfg(not(test))] -use althea_kernel_interface::LinuxCommandRunner; -#[cfg(test)] -use althea_kernel_interface::TestCommandRunner; use althea_types::Identity; use failure::Error; -use owning_ref::{RwLockReadGuardRef, RwLockWriteGuardRefMut}; -use serde::{Deserialize, Serialize}; +use network::NetworkSettings; +use payment::PaymentSettings; +use serde::Serialize; use serde_json::Value; use std::fs::File; use std::io::Write; -#[cfg(test)] -use std::sync::Mutex; use std::sync::{Arc, RwLock}; use std::thread; use std::time::Duration; @@ -45,49 +36,187 @@ pub mod logging; pub mod network; pub mod operator; pub mod payment; +// pub mod tower; + +use crate::client::RitaClientSettings; +use crate::exit::RitaExitSettingsStruct; -#[cfg(test)] lazy_static! { - static ref KI: Box = Box::new(TestCommandRunner { - run_command: Arc::new(Mutex::new(Box::new(|_program, _args| { - panic!("kernel interface used before initialized"); - }))) - }); + static ref EXIT_SETTING: Arc>> = + Arc::new(RwLock::new(None)); } -#[cfg(not(test))] lazy_static! { - /// This is the network settings for rita and rita_exit which generally only applies to networking - /// _within_ the mesh or setting up pre hop tunnels (so nothing on exits) - static ref KI: Box = Box::new(LinuxCommandRunner {}); + static ref CLIENT_SETTING: Arc>> = + Arc::new(RwLock::new(None)); +} + +lazy_static! { + static ref GIT_HASH: Arc> = Arc::new(RwLock::new(String::new())); +} + +lazy_static! { + static ref FLAG_CONFIG: Arc> = Arc::new(RwLock::new(String::new())); +} + +pub struct RitaSettings { + payment: PaymentSettings, + network: NetworkSettings, + identity: Option, +} + +impl RitaSettings { + pub fn get_payment(&self) -> PaymentSettings { + self.payment.clone() + } + pub fn get_network(&self) -> NetworkSettings { + self.network.clone() + } + pub fn get_identity(&self) -> Option { + self.identity + } + pub fn set_payment(&mut self, payment: PaymentSettings) { + self.payment = payment; + } + pub fn set_network(&mut self, network: NetworkSettings) { + self.network = network; + } + pub fn set_identity(&mut self, id: Identity) { + self.identity = Some(id); + } +} + +pub fn write_config() -> Result<(), Error> { + let client_settings = &mut *CLIENT_SETTING.write().unwrap(); + let exit_settings = &mut *EXIT_SETTING.write().unwrap(); + let filename = FLAG_CONFIG.read().unwrap(); + match (client_settings, exit_settings) { + (Some(client), None) => client.write(&filename), + (None, Some(exit)) => exit.write(&filename), + (Some(_), Some(_)) => { + panic!("Both types of config are loaded, this is impossible in production!") + } + (None, None) => panic!("No config has been loaded, check init"), + } +} + +pub fn get_config_json() -> Result { + let client_settings = &mut *CLIENT_SETTING.write().unwrap(); + let exit_settings = &mut *EXIT_SETTING.write().unwrap(); + match (client_settings, exit_settings) { + (Some(client), None) => client.get_all(), + (None, Some(exit)) => exit.get_all(), + (Some(_), Some(_)) => { + panic!("Both types of config are loaded, this is impossible in production!") + } + (None, None) => panic!("No config has been loaded, check init"), + } +} + +pub fn merge_config_json(changed_settings: serde_json::Value) -> Result<(), Error> { + let client_settings = &mut *CLIENT_SETTING.write().unwrap(); + let exit_settings = &mut *EXIT_SETTING.write().unwrap(); + match (client_settings, exit_settings) { + (Some(client), None) => client.merge(changed_settings), + (None, Some(exit)) => exit.merge(changed_settings), + (Some(_), Some(_)) => { + panic!("Both types of config are loaded, this is impossible in production!") + } + (None, None) => panic!("No config has been loaded, check init"), + } +} + +/// Set the RitaClientSettings Struct or RitaExitSettingsStruct +/// depending on which one is called from the argument parameter +/// does not currently save the identity paramater, as we don't +/// need to modify that in a generic context. +pub fn set_rita_common(input: RitaSettings) { + let client_settings = &mut *CLIENT_SETTING.write().unwrap(); + let exit_settings = &mut *EXIT_SETTING.write().unwrap(); + match (client_settings, exit_settings) { + (Some(client), None) => { + client.network = input.network; + client.payment = input.payment; + } + // do the other way around for rita exit, panic if both are Some() + // if both are none also panic becuase rita_client or rita_exit must first + // initialize + (None, Some(exit)) => { + exit.network = input.network; + exit.payment = input.payment; + } + (Some(_), Some(_)) => { + panic!("Both types of config are loaded, this is impossible in production!") + } + (None, None) => panic!("No config has been loaded, check init"), + } } -pub trait RitaCommonSettings> { - fn get_payment<'ret, 'me: 'ret>(&'me self) -> RwLockReadGuardRef<'ret, T, PaymentSettings>; - fn get_payment_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, T, PaymentSettings>; +/// Get the RitaClientSettingsStruct or RitaExitSettingsStruct +/// depending on which one is set +pub fn get_rita_common() -> RitaSettings { + let client_settings = &*CLIENT_SETTING.read().unwrap(); + let exit_settings = &*EXIT_SETTING.read().unwrap(); + match (client_settings, exit_settings) { + (Some(client), None) => RitaSettings { + network: client.get_network(), + payment: client.get_payment(), + identity: client.get_identity(), + }, + (None, Some(exit)) => RitaSettings { + network: exit.get_network(), + payment: exit.get_payment(), + identity: exit.get_identity(), + }, + (Some(_), Some(_)) => panic!("Rita_common cannot be both exit and client"), + (None, None) => panic!("Both types are none. One needs to be initalized!"), + } +} - fn get_localization<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockReadGuardRef<'ret, T, LocalizationSettings>; - fn get_localization_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, T, LocalizationSettings>; +pub fn set_git_hash(git_hash: String) { + *GIT_HASH.write().unwrap() = git_hash; +} - fn get_network<'ret, 'me: 'ret>(&'me self) -> RwLockReadGuardRef<'ret, T, NetworkSettings>; - fn get_network_mut<'ret, 'me: 'ret>( - &'me self, - ) -> RwLockWriteGuardRefMut<'ret, T, NetworkSettings>; +pub fn get_git_hash() -> String { + let ret = &*GIT_HASH.read().unwrap(); + ret.clone() +} - fn merge(&self, changed_settings: Value) -> Result<(), Error>; - fn get_all(&self) -> Result; +pub fn set_flag_config(flag_config: String) { + *FLAG_CONFIG.write().unwrap() = flag_config; +} + +pub fn get_flag_config() -> String { + let ret = &*FLAG_CONFIG.read().unwrap(); + ret.clone() +} + +pub fn set_rita_client(client_setting: RitaClientSettings) { + *CLIENT_SETTING.write().unwrap() = Some(client_setting); +} + +/// This function retrieves the rita client binary settings. +pub fn get_rita_client() -> RitaClientSettings { + let temp = &*CLIENT_SETTING.read().unwrap(); + let ret = match temp { + Some(val) => val, + None => panic!("Attempted to get_rita_client() before initialization"), + }; + ret.clone() +} - // Can be None if the mesh ip was not configured yet - fn get_identity(&self) -> Option; +pub fn set_rita_exit(exit_setting: RitaExitSettingsStruct) { + *EXIT_SETTING.write().unwrap() = Some(exit_setting); +} - fn get_future(&self) -> bool; - fn set_future(&self, future: bool); +/// This function retrieves the rita exit binary settings. +pub fn get_rita_exit() -> RitaExitSettingsStruct { + let temp = &*EXIT_SETTING.read().unwrap(); + let ret = match temp { + Some(val) => val, + None => panic!("Attempted to get_rita_exit() before initialization"), + }; + ret.clone() } /// This merges 2 json objects, overwriting conflicting values in `a` @@ -108,24 +237,50 @@ pub trait FileWrite { fn write(&self, file_name: &str) -> Result<(), Error>; } -fn spawn_watch_thread<'de, T: 'static>(settings: Arc>, file_path: &str) -where - T: serde::Deserialize<'de> + Sync + Send + std::fmt::Debug + Clone + Eq + FileWrite, -{ +/// Spawns a thread that will grab a copy of the updated RitaSettings +/// struct and then write it to the disk, if it changes every so often +/// currently this period is 600 seconds or 10 minutes per write. The value +/// should be kept low on routers due to low write endurance of storage +fn spawn_watch_thread_client(settings: RitaClientSettings, file_path: &str) { + let file_path = file_path.to_string(); + + thread::spawn(move || { + let mut old_settings = settings.clone(); + loop { + thread::sleep(Duration::from_secs(600)); + + let new_settings = get_rita_client(); + + if old_settings != new_settings { + if let Err(e) = new_settings.write(&file_path) { + warn!("writing updated config failed {:?}", e); + } + old_settings = new_settings.clone(); + } + } + }); +} + +/// Spawns a thread that will grab a copy of the updated RitaSettings +/// struct and then write it to the disk, if it changes every so often +/// currently this period is 600 seconds or 10 minutes per write. The value +/// should be kept low on routers due to low write endurance of storage +fn spawn_watch_thread_exit(settings: RitaExitSettingsStruct, file_path: &str) { let file_path = file_path.to_string(); thread::spawn(move || { - let old_settings = settings.read().unwrap().clone(); + let mut old_settings = settings.clone(); loop { thread::sleep(Duration::from_secs(600)); - let new_settings = settings.read().unwrap().clone(); + let new_settings = get_rita_exit(); if old_settings != new_settings { trace!("writing updated config: {:?}", new_settings); - if let Err(e) = settings.read().unwrap().write(&file_path) { + if let Err(e) = new_settings.write(&file_path) { warn!("writing updated config failed {:?}", e); } + old_settings = new_settings.clone(); } } }); @@ -143,24 +298,23 @@ where file.flush().unwrap(); file.sync_all().unwrap(); drop(file); - KI.fs_sync()?; Ok(()) } } #[cfg(test)] mod tests { - use crate::client::RitaSettingsStruct; + use crate::client::RitaClientSettings; use crate::exit::RitaExitSettingsStruct; #[test] fn test_settings_test() { - RitaSettingsStruct::new("test.toml").unwrap(); + RitaClientSettings::new("test.toml").unwrap(); } #[test] fn test_settings_example() { - RitaSettingsStruct::new("example.toml").unwrap(); + RitaClientSettings::new("example.toml").unwrap(); } #[test]