build + tor: update grin libs fix android build, add arti lib, tor server config, connection with snowflake, transport at connections
This commit is contained in:
parent
f095fa5ae0
commit
7207fb56bc
12 changed files with 3436 additions and 268 deletions
3236
Cargo.lock
generated
3236
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
43
Cargo.toml
43
Cargo.toml
|
@ -16,21 +16,21 @@ log = "0.4"
|
|||
|
||||
## node
|
||||
openssl-sys = { version = "0.9.82", features = ["vendored"] }
|
||||
grin_api = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_chain = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_config = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_core = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_p2p = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_servers = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_keychain = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_util = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
grin_api = "5.3.0"
|
||||
grin_chain = "5.3.0"
|
||||
grin_config = "5.3.0"
|
||||
grin_core = "5.3.0"
|
||||
grin_p2p = "5.3.0"
|
||||
grin_servers = "5.3.0"
|
||||
grin_keychain = "5.3.0"
|
||||
grin_util = "5.3.0"
|
||||
|
||||
## wallet
|
||||
grin_wallet_impls = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
||||
grin_wallet_api = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
||||
grin_wallet_libwallet = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
||||
grin_wallet_util = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
||||
grin_wallet_controller = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
||||
grin_wallet_impls = "5.3.0"
|
||||
grin_wallet_api = "5.3.0"
|
||||
grin_wallet_libwallet = "5.3.0"
|
||||
grin_wallet_util = "5.3.0"
|
||||
grin_wallet_controller = "5.3.0"
|
||||
|
||||
## ui
|
||||
egui = { version = "0.27.2", default-features = false }
|
||||
|
@ -38,6 +38,7 @@ egui_extras = { version = "0.27.2", features = ["image"] }
|
|||
rust-i18n = "2.3.1"
|
||||
|
||||
## other
|
||||
anyhow = "1.0.75"
|
||||
thiserror = "1.0.58"
|
||||
futures = "0.3"
|
||||
dirs = "5.0.1"
|
||||
|
@ -48,13 +49,20 @@ toml = "0.8.2"
|
|||
serde = "1.0.170"
|
||||
local-ip-address = "0.6.1"
|
||||
url = "2.4.0"
|
||||
|
||||
## stratum server
|
||||
rand = "0.8.5"
|
||||
serde_derive = "1.0.197"
|
||||
serde_json = "1.0.115"
|
||||
tokio = {version = "1.29.1", features = ["full"] }
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
|
||||
## tor
|
||||
arti = { version = "1.2.0", features = ["experimental-api", "pt-client", "static"] }
|
||||
arti-client = { version = "0.17.0", features = ["experimental-api", "pt-client", "static"] }
|
||||
tor-rtcompat = { version = "0.17.0", features = ["static"] }
|
||||
tor-config = "0.17.0"
|
||||
fs-mistrust = "0.7.9"
|
||||
|
||||
## stratum server
|
||||
tokio-util = { version = "0.7.8", features = ["codec"] }
|
||||
rand = "0.8.5"
|
||||
|
||||
[build-dependencies]
|
||||
built = { version = "0.7.0", features = ["git2"]}
|
||||
|
@ -70,5 +78,6 @@ image = "0.25.1"
|
|||
android_logger = "0.13.1"
|
||||
jni = "0.21.1"
|
||||
android-activity = "0.5.2"
|
||||
wgpu = "0.19"
|
||||
winit = { version = "0.29", features = [ "android-game-activity" ] }
|
||||
eframe = { version = "0.27.2", features = [ "wgpu", "android-game-activity" ] }
|
|
@ -40,6 +40,7 @@ public class MainActivity extends GameActivity {
|
|||
try {
|
||||
Os.setenv("HOME", getExternalFilesDir("").getPath(), true);
|
||||
Os.setenv("XDG_CACHE_HOME", getExternalCacheDir().getPath(), true);
|
||||
Os.setenv("ARTI_FS_DISABLE_PERMISSION_CHECKS", "true", true);
|
||||
} catch (ErrnoException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
|
|
@ -126,6 +126,12 @@ network:
|
|||
available: Available
|
||||
not_available: Not available
|
||||
availability_check: Availability check
|
||||
tor_network: Tor network
|
||||
server_enabled: Server enabled
|
||||
server_starting: Server is starting
|
||||
server_stopping: Server is stopping
|
||||
server_error: Server error
|
||||
server_disabled: Server disabled
|
||||
sync_status:
|
||||
node_restarting: Node is restarting
|
||||
node_down: Node is down
|
||||
|
|
|
@ -126,6 +126,12 @@ network:
|
|||
available: Доступно
|
||||
not_available: Недоступно
|
||||
availability_check: Проверка доступности
|
||||
tor_network: Сеть Tor
|
||||
server_enabled: Сервер включен
|
||||
server_starting: Сервер запускается
|
||||
server_stopping: Сервер останавливается
|
||||
server_error: Ошибка сервера
|
||||
server_disabled: Сервер отключен
|
||||
sync_status:
|
||||
node_restarting: Узел перезапускается
|
||||
node_down: Узел выключен
|
||||
|
|
|
@ -17,11 +17,12 @@ use url::Url;
|
|||
|
||||
use crate::AppConfig;
|
||||
use crate::gui::Colors;
|
||||
use crate::gui::icons::{CARET_RIGHT, CHECK_CIRCLE, COMPUTER_TOWER, DOTS_THREE_CIRCLE, PENCIL, POWER, TRASH, X_CIRCLE};
|
||||
use crate::gui::icons::{CARET_RIGHT, CHECK_CIRCLE, COMPUTER_TOWER, DOTS_THREE_CIRCLE, GEAR_SIX, PENCIL, POWER, TRASH, WARNING_CIRCLE, X_CIRCLE};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::{Modal, NodeSetup, View};
|
||||
use crate::gui::views::types::{ModalContainer, ModalPosition, TextEditOptions};
|
||||
use crate::node::{Node, NodeConfig};
|
||||
use crate::tor::{TorServer, TorServerConfig};
|
||||
use crate::wallet::{ConnectionsConfig, ExternalConnection};
|
||||
|
||||
/// Network connections content.
|
||||
|
@ -99,12 +100,21 @@ impl ConnectionsContent {
|
|||
// Show integrated node info content.
|
||||
Self::integrated_node_item_ui(ui);
|
||||
|
||||
// Show transport connections.
|
||||
ui.add_space(6.0);
|
||||
let transport_text = format!("{}:", t!("wallets.transport"));
|
||||
ui.label(RichText::new(transport_text).size(16.0).color(Colors::GRAY));
|
||||
ui.add_space(6.0);
|
||||
|
||||
// Show Tor SOCKS server.
|
||||
Self::tor_transport_item_ui(ui);
|
||||
|
||||
// Show external connections.
|
||||
let ext_conn_list = ConnectionsConfig::ext_conn_list();
|
||||
if !ext_conn_list.is_empty() {
|
||||
ui.add_space(6.0);
|
||||
ui.label(RichText::new(t!("wallets.ext_conn")).size(16.0).color(Colors::GRAY));
|
||||
ui.add_space(6.0);
|
||||
// Show external connections.
|
||||
for (index, conn) in ext_conn_list.iter().enumerate() {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
// Draw connection list item.
|
||||
|
@ -114,6 +124,67 @@ impl ConnectionsContent {
|
|||
}
|
||||
}
|
||||
|
||||
/// Draw Tor connection item content.
|
||||
fn tor_transport_item_ui(ui: &mut egui::Ui) {
|
||||
// Draw round background.
|
||||
let mut rect = ui.available_rect_before_wrap();
|
||||
rect.set_height(78.0);
|
||||
let rounding = View::item_rounding(0, 1, false);
|
||||
ui.painter().rect(rect, rounding, Colors::FILL, View::ITEM_STROKE);
|
||||
|
||||
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||
// Draw button to show Tor connection settings.
|
||||
View::item_button(ui, View::item_rounding(0, 1, true), GEAR_SIX, None, || {
|
||||
AppConfig::toggle_show_connections_network_panel();
|
||||
});
|
||||
|
||||
// Draw buttons to stop or start Tor server.
|
||||
if !TorServer::is_stopping() && !TorServer::is_starting() {
|
||||
if TorServer::is_running() {
|
||||
View::item_button(ui, Rounding::default(), POWER, Some(Colors::RED), || {
|
||||
TorServer::stop();
|
||||
});
|
||||
} else {
|
||||
View::item_button(ui, Rounding::default(), POWER, Some(Colors::GREEN), || {
|
||||
TorServer::start();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let layout_size = ui.available_size();
|
||||
ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| {
|
||||
ui.add_space(6.0);
|
||||
ui.vertical(|ui| {
|
||||
ui.add_space(3.0);
|
||||
ui.label(RichText::new(t!("network.tor_network"))
|
||||
.size(18.0)
|
||||
.color(Colors::TITLE));
|
||||
|
||||
// Setup SOCKS server address.
|
||||
let socks_port = TorServerConfig::socks_port();
|
||||
let addr_text = format!("{} http://127.0.0.1:{}", COMPUTER_TOWER, socks_port);
|
||||
ui.label(RichText::new(addr_text).size(15.0).color(Colors::TEXT));
|
||||
ui.add_space(1.0);
|
||||
|
||||
// Setup server status text.
|
||||
let (status_icon, status_text) = if TorServer::has_error() {
|
||||
(WARNING_CIRCLE, t!("network.server_error"))
|
||||
} else if TorServer::is_starting() {
|
||||
(DOTS_THREE_CIRCLE, t!("network.server_starting"))
|
||||
} else if TorServer::is_stopping() {
|
||||
(DOTS_THREE_CIRCLE, t!("network.server_stopping"))
|
||||
} else if TorServer::is_running() {
|
||||
(CHECK_CIRCLE, t!("network.server_enabled"))
|
||||
} else {
|
||||
(X_CIRCLE, t!("network.server_disabled"))
|
||||
};
|
||||
let status_text = format!("{} {}", status_icon, status_text);
|
||||
ui.label(RichText::new(status_text).size(15.0).color(Colors::GRAY));
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// Draw integrated node connection item content.
|
||||
fn integrated_node_item_ui(ui: &mut egui::Ui) {
|
||||
// Draw round background.
|
||||
|
@ -123,9 +194,6 @@ impl ConnectionsContent {
|
|||
ui.painter().rect(rect, rounding, Colors::FILL, View::ITEM_STROKE);
|
||||
|
||||
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||
// Setup padding for item buttons.
|
||||
ui.style_mut().spacing.button_padding = egui::vec2(14.0, 0.0);
|
||||
|
||||
// Draw button to show integrated node info.
|
||||
View::item_button(ui, View::item_rounding(0, 1, true), CARET_RIGHT, None, || {
|
||||
AppConfig::toggle_show_connections_network_panel();
|
||||
|
@ -137,7 +205,7 @@ impl ConnectionsContent {
|
|||
Node::start();
|
||||
});
|
||||
} else if !Node::is_starting() && !Node::is_stopping() && !Node::is_restarting() {
|
||||
// Draw button to open closed wallet.
|
||||
// Draw button to stop integrated node.
|
||||
View::item_button(ui, Rounding::default(), POWER, Some(Colors::RED), || {
|
||||
Node::stop(false);
|
||||
});
|
||||
|
|
|
@ -22,6 +22,7 @@ use crate::gui::views::{ConnectionsContent, NetworkMetrics, NetworkMining, Netwo
|
|||
use crate::gui::views::network::types::{NetworkTab, NetworkTabType};
|
||||
use crate::gui::views::types::{TitleContentType, TitleType};
|
||||
use crate::node::Node;
|
||||
use crate::tor::TorServer;
|
||||
use crate::wallet::ExternalConnection;
|
||||
|
||||
/// Network content.
|
||||
|
@ -147,7 +148,8 @@ impl NetworkContent {
|
|||
});
|
||||
|
||||
// Redraw after delay if node is syncing to update stats.
|
||||
if Node::is_running() {
|
||||
if Node::is_running() || TorServer::is_running() || TorServer::is_starting() ||
|
||||
TorServer::is_stopping() {
|
||||
ui.ctx().request_repaint_after(Node::STATS_UPDATE_DELAY);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ i18n!("locales");
|
|||
|
||||
mod node;
|
||||
mod wallet;
|
||||
|
||||
mod tor;
|
||||
mod settings;
|
||||
pub mod gui;
|
||||
|
||||
|
@ -63,8 +63,9 @@ fn android_main(app: AndroidApp) {
|
|||
|
||||
let width = app.config().screen_width_dp().unwrap() as f32;
|
||||
let height = app.config().screen_height_dp().unwrap() as f32;
|
||||
let size = egui::emath::vec2(width, height);
|
||||
let mut options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default().with_inner_size(vec2(width, height)),
|
||||
viewport: egui::ViewportBuilder::default().with_inner_size(size),
|
||||
..Default::default()
|
||||
};
|
||||
// Setup limits that are guaranteed to be compatible with Android devices.
|
||||
|
|
|
@ -24,6 +24,7 @@ use serde::Serialize;
|
|||
|
||||
use crate::node::NodeConfig;
|
||||
use crate::settings::AppConfig;
|
||||
use crate::tor::TorServerConfig;
|
||||
use crate::wallet::ConnectionsConfig;
|
||||
|
||||
lazy_static! {
|
||||
|
@ -42,18 +43,27 @@ pub struct Settings {
|
|||
node_config: Arc<RwLock<NodeConfig>>,
|
||||
/// Wallet connections configuration.
|
||||
conn_config: Arc<RwLock<ConnectionsConfig>>,
|
||||
/// Tor server configuration.
|
||||
tor_config: Arc<RwLock<TorServerConfig>>
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
/// Initialize settings with app and node configs.
|
||||
fn init() -> Self {
|
||||
// Initialize app config.
|
||||
let app_config_path = Settings::get_config_path(AppConfig::FILE_NAME, None);
|
||||
let app_config = Self::init_config::<AppConfig>(app_config_path);
|
||||
|
||||
// Initialize tor config.
|
||||
let tor_config_path = Settings::get_config_path(TorServerConfig::FILE_NAME, None);
|
||||
let tor_config = Self::init_config::<TorServerConfig>(tor_config_path);
|
||||
|
||||
let chain_type = &app_config.chain_type;
|
||||
Self {
|
||||
node_config: Arc::new(RwLock::new(NodeConfig::for_chain_type(chain_type))),
|
||||
conn_config: Arc::new(RwLock::new(ConnectionsConfig::for_chain_type(chain_type))),
|
||||
app_config: Arc::new(RwLock::new(app_config)),
|
||||
tor_config: Arc::new(RwLock::new(tor_config)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,6 +109,16 @@ impl Settings {
|
|||
SETTINGS_STATE.conn_config.write().unwrap()
|
||||
}
|
||||
|
||||
/// Get tor server configuration to read values.
|
||||
pub fn tor_config_to_read() -> RwLockReadGuard<'static, TorServerConfig> {
|
||||
SETTINGS_STATE.tor_config.read().unwrap()
|
||||
}
|
||||
|
||||
/// Get tor server configuration to update values.
|
||||
pub fn tor_config_to_update() -> RwLockWriteGuard<'static, TorServerConfig> {
|
||||
SETTINGS_STATE.tor_config.write().unwrap()
|
||||
}
|
||||
|
||||
/// Get base directory path for configuration.
|
||||
pub fn get_base_path(sub_dir: Option<String>) -> PathBuf {
|
||||
// Check if dir exists.
|
||||
|
|
56
src/tor/config.rs
Normal file
56
src/tor/config.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright 2024 The Grim Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use crate::Settings;
|
||||
|
||||
/// Tor SOCKS proxy server configuration.
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct TorServerConfig {
|
||||
socks_port: u16
|
||||
}
|
||||
|
||||
/// Default SOCKS port value.
|
||||
const DEFAULT_SOCKS_PORT: u16 = 9060;
|
||||
|
||||
impl Default for TorServerConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
socks_port: DEFAULT_SOCKS_PORT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TorServerConfig {
|
||||
/// Application configuration file name.
|
||||
pub const FILE_NAME: &'static str = "app.toml";
|
||||
|
||||
/// Save application configuration to the file.
|
||||
pub fn save(&self) {
|
||||
Settings::write_to_file(self, Settings::get_config_path(Self::FILE_NAME, None));
|
||||
}
|
||||
|
||||
/// Get SOCKS port value.
|
||||
pub fn socks_port() -> u16 {
|
||||
let r_config = Settings::tor_config_to_read();
|
||||
r_config.socks_port
|
||||
}
|
||||
|
||||
/// Save SOCKS port value.
|
||||
pub fn save_socks_port(port: u16) {
|
||||
let mut w_config = Settings::tor_config_to_update();
|
||||
w_config.socks_port = port;
|
||||
w_config.save();
|
||||
}
|
||||
}
|
19
src/tor/mod.rs
Normal file
19
src/tor/mod.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2024 The Grim Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
mod config;
|
||||
pub use config::TorServerConfig;
|
||||
|
||||
mod tor;
|
||||
pub use tor::TorServer;
|
228
src/tor/tor.rs
Normal file
228
src/tor/tor.rs
Normal file
|
@ -0,0 +1,228 @@
|
|||
// Copyright 2024 The Grim Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use lazy_static::lazy_static;
|
||||
use arti::socks::run_socks_proxy;
|
||||
use arti_client::{TorClient, TorClientConfig};
|
||||
use arti_client::config::pt::{TransportConfigBuilder};
|
||||
use arti_client::config::{BridgeConfigBuilder, TorClientConfigBuilder, StorageConfigBuilder};
|
||||
use futures::task::SpawnExt;
|
||||
use tokio::task::JoinHandle;
|
||||
use anyhow::{Result};
|
||||
use tokio::time::sleep;
|
||||
use tor_config::{CfgPath, Listen};
|
||||
use tor_rtcompat::{BlockOn, Runtime};
|
||||
use tor_rtcompat::tokio::TokioNativeTlsRuntime;
|
||||
|
||||
use crate::tor::TorServerConfig;
|
||||
|
||||
lazy_static! {
|
||||
/// Static thread-aware state of [`Node`] to be updated from separate thread.
|
||||
static ref TOR_SERVER_STATE: Arc<TorServer> = Arc::new(TorServer::default());
|
||||
}
|
||||
|
||||
/// Tor SOCKS proxy server.
|
||||
pub struct TorServer {
|
||||
/// Flag to check if server is running.
|
||||
running: AtomicBool,
|
||||
/// Flag to check if server is starting.
|
||||
starting: AtomicBool,
|
||||
/// Flag to check if server needs to stop.
|
||||
stopping: AtomicBool,
|
||||
/// Flag to check if error happened.
|
||||
error: AtomicBool,
|
||||
/// Tor client to use for proxy.
|
||||
client: Arc<RwLock<Option<TorClient<TokioNativeTlsRuntime>>>>
|
||||
}
|
||||
|
||||
impl Default for TorServer {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
running: AtomicBool::new(false),
|
||||
starting: AtomicBool::new(false),
|
||||
stopping: AtomicBool::new(false),
|
||||
error: AtomicBool::new(false),
|
||||
client: Arc::new(RwLock::new(None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TorServer {
|
||||
/// Check if server is running.
|
||||
pub fn is_running() -> bool {
|
||||
TOR_SERVER_STATE.running.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Check if server is running.
|
||||
pub fn is_starting() -> bool {
|
||||
TOR_SERVER_STATE.starting.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Check if server is stopping.
|
||||
pub fn is_stopping() -> bool {
|
||||
TOR_SERVER_STATE.stopping.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Check if server has error.
|
||||
pub fn has_error() -> bool {
|
||||
TOR_SERVER_STATE.error.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Stop the server.
|
||||
pub fn stop() {
|
||||
TOR_SERVER_STATE.stopping.store(true, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// Start or restart the server if already running.
|
||||
pub fn start() {
|
||||
if Self::is_running() {
|
||||
Self::stop();
|
||||
}
|
||||
|
||||
thread::spawn(|| {
|
||||
while Self::is_stopping() {
|
||||
thread::sleep(Duration::from_millis(1000));
|
||||
}
|
||||
TOR_SERVER_STATE.starting.store(true, Ordering::Relaxed);
|
||||
TOR_SERVER_STATE.error.store(false, Ordering::Relaxed);
|
||||
|
||||
// Check if Tor client is already running.
|
||||
if TOR_SERVER_STATE.client.read().unwrap().is_some() {
|
||||
let r_client = TOR_SERVER_STATE.client.read().unwrap();
|
||||
let runtime = TokioNativeTlsRuntime::create().unwrap();
|
||||
let _ = runtime.clone().block_on(
|
||||
Self::launch_socks_proxy(runtime, r_client.as_ref().unwrap().clone())
|
||||
);
|
||||
} else {
|
||||
// Create Tor client config to connect.
|
||||
let mut builder = TorClientConfig::builder();
|
||||
|
||||
// Setup Snowflake bridges.
|
||||
Self::setup_bridges(&mut builder);
|
||||
|
||||
// Create Tor client from config.
|
||||
if let Ok(config) = builder.build() {
|
||||
// Restart server on connection timeout.
|
||||
thread::spawn(|| {
|
||||
thread::sleep(Duration::from_millis(30000));
|
||||
let r_client = TOR_SERVER_STATE.client.read().unwrap();
|
||||
if r_client.is_none() {
|
||||
Self::start();
|
||||
}
|
||||
});
|
||||
// Create Tor client.
|
||||
let runtime = TokioNativeTlsRuntime::create().unwrap();
|
||||
match TorClient::with_runtime(runtime.clone())
|
||||
.config(config)
|
||||
.bootstrap_behavior(arti_client::BootstrapBehavior::OnDemand)
|
||||
.create_unbootstrapped() {
|
||||
Ok(tor_client) => {
|
||||
let mut w_client = TOR_SERVER_STATE.client.write().unwrap();
|
||||
if w_client.is_some() {
|
||||
return;
|
||||
}
|
||||
*w_client = Some(tor_client.clone());
|
||||
let _ = runtime.clone().block_on(
|
||||
// Launch SOCKS proxy server.
|
||||
Self::launch_socks_proxy(runtime, tor_client)
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("{}", e);
|
||||
TOR_SERVER_STATE.starting.store(false, Ordering::Relaxed);
|
||||
TOR_SERVER_STATE.error.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TOR_SERVER_STATE.starting.store(false, Ordering::Relaxed);
|
||||
TOR_SERVER_STATE.error.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Launch SOCKS proxy server.
|
||||
async fn launch_socks_proxy<R: Runtime>(runtime: R, tor_client: TorClient<R>) -> Result<()> {
|
||||
let proxy_handle: JoinHandle<Result<()>> = tokio::spawn(
|
||||
run_socks_proxy(
|
||||
runtime,
|
||||
tor_client,
|
||||
Listen::new_localhost(TorServerConfig::socks_port()),
|
||||
)
|
||||
);
|
||||
|
||||
// Setup server state flags.
|
||||
TOR_SERVER_STATE.starting.store(false, Ordering::Relaxed);
|
||||
TOR_SERVER_STATE.running.store(true, Ordering::Relaxed);
|
||||
|
||||
loop {
|
||||
if Self::is_stopping() || proxy_handle.is_finished() {
|
||||
proxy_handle.abort();
|
||||
TOR_SERVER_STATE.stopping.store(false, Ordering::Relaxed);
|
||||
TOR_SERVER_STATE.running.store(false, Ordering::Relaxed);
|
||||
return Ok(());
|
||||
}
|
||||
sleep(Duration::from_millis(3000)).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// Setup Tor Snowflake bridges.
|
||||
fn setup_bridges(builder: &mut TorClientConfigBuilder) {
|
||||
// Add a single bridge to the list of bridges, from a bridge line.
|
||||
// This line comes from https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/blob/main/projects/common/bridges_list.snowflake.txt
|
||||
// this is a real bridge line you can use as-is, after making sure it's still up to date with
|
||||
// above link.
|
||||
const BRIDGE1_LINE: &str = "Bridge snowflake 192.0.2.3:80 2B280B23E1107BB62ABFC40DDCC8824814F80A72 fingerprint=2B280B23E1107BB62ABFC40DDCC8824814F80A72 url=https://snowflake-broker.torproject.net.global.prod.fastly.net/ front=cdn.sstatic.net ice=stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.com:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellorandomizedalpn";
|
||||
let bridge_1: BridgeConfigBuilder = BRIDGE1_LINE.parse().unwrap();
|
||||
builder.bridges().bridges().push(bridge_1);
|
||||
|
||||
// Add a second bridge, built by hand. We use the 2nd bridge line from above, but modify some
|
||||
// parameters to use AMP Cache instead of Fastly as a signaling channel. The difference in
|
||||
// configuration is detailed in
|
||||
// https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/tree/main/client#amp-cache
|
||||
let mut bridge2_builder = BridgeConfigBuilder::default();
|
||||
bridge2_builder
|
||||
.transport("snowflake")
|
||||
.push_setting(
|
||||
"fingerprint",
|
||||
"8838024498816A039FCBBAB14E6F40A0843051FA"
|
||||
)
|
||||
.push_setting("url", "https://snowflake-broker.torproject.net/")
|
||||
.push_setting("ampcache", "https://cdn.ampproject.org/")
|
||||
.push_setting("front", "www.google.com")
|
||||
.push_setting(
|
||||
"ice",
|
||||
"stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.net:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478",
|
||||
)
|
||||
.push_setting("utls-imitate", "hellorandomizedalpn");
|
||||
bridge2_builder.set_addrs(vec!["192.0.2.4:80".parse().unwrap()]);
|
||||
bridge2_builder.set_ids(vec!["8838024498816A039FCBBAB14E6F40A0843051FA".parse().unwrap()]);
|
||||
// Now insert the second bridge into our config builder.
|
||||
builder.bridges().bridges().push(bridge2_builder);
|
||||
|
||||
// Now configure an snowflake transport. (Requires the "pt-client" feature)
|
||||
let mut transport = TransportConfigBuilder::default();
|
||||
transport
|
||||
.protocols(vec!["snowflake".parse().unwrap()])
|
||||
// this might be named differently on some systems, this should work on Debian,
|
||||
// but Archlinux is known to use `snowflake-pt-client` instead for instance.
|
||||
.path(CfgPath::new("snowflake-client".into()))
|
||||
.run_on_startup(true);
|
||||
builder.bridges().transports().push(transport);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue