start, reverse guard, cli-frontend for server and client

This commit is contained in:
2026-01-01 18:54:36 +03:00
commit 5fbb32d243
30 changed files with 4700 additions and 0 deletions

23
ostp-server/Cargo.toml Normal file
View File

@@ -0,0 +1,23 @@
[package]
name = "ostp-server"
version.workspace = true
edition.workspace = true
description = "OSTP Stealth VPN Server"
[[bin]]
name = "ostp-server"
path = "src/main.rs"
[dependencies]
ostp = { path = "../ostp" }
oncp = { path = "../oncp" }
ostp-guard = { path = "../ostp-guard" }
tokio.workspace = true
anyhow.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
clap.workspace = true
hex.workspace = true
serde.workspace = true
serde_json.workspace = true
rand.workspace = true

164
ostp-server/src/main.rs Normal file
View File

@@ -0,0 +1,164 @@
//! OSTP Server CLI - Stealth VPN Server for Linux
//!
//! Usage:
//! ostp-server --listen 0.0.0.0:8443 --psk <hex-key>
//! ostp-server --config /etc/ostp/server.json
use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
use ostp::{OstpServer, ServerConfig};
use ostp_guard::error_codes;
use std::net::SocketAddr;
use std::path::PathBuf;
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
#[derive(Parser)]
#[command(name = "ostp-server")]
#[command(author = "Ospab Team")]
#[command(version)]
#[command(about = "OSTP Stealth VPN Server", long_about = None)]
struct Cli {
#[command(subcommand)]
command: Option<Commands>,
/// Listen address (e.g., 0.0.0.0:8443)
#[arg(short, long, default_value = "0.0.0.0:8443")]
listen: SocketAddr,
/// Pre-shared key in hex format (64 hex chars = 32 bytes)
#[arg(short, long, env = "OSTP_PSK")]
psk: Option<String>,
/// Path to config file (JSON)
#[arg(short, long)]
config: Option<PathBuf>,
/// Log level (trace, debug, info, warn, error)
#[arg(long, default_value = "info")]
log_level: String,
/// Max concurrent connections
#[arg(long, default_value = "1024")]
max_connections: usize,
}
#[derive(Subcommand)]
enum Commands {
/// Generate a new random PSK
GenKey,
/// Show server status (placeholder)
Status,
}
#[derive(serde::Deserialize, serde::Serialize)]
struct ConfigFile {
listen: String,
psk: String,
max_connections: Option<usize>,
log_level: Option<String>,
}
fn setup_logging(level: &str) {
let filter = EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new(level));
tracing_subscriber::registry()
.with(fmt::layer().with_target(true).with_thread_ids(false))
.with(filter)
.init();
}
fn parse_psk(hex_str: &str) -> Result<[u8; 32]> {
let bytes = hex::decode(hex_str.trim())
.context("Invalid hex string for PSK")?;
if bytes.len() != 32 {
anyhow::bail!("PSK must be exactly 32 bytes (64 hex characters), got {}", bytes.len());
}
let mut psk = [0u8; 32];
psk.copy_from_slice(&bytes);
Ok(psk)
}
fn generate_random_psk() -> String {
let psk: [u8; 32] = rand::random();
hex::encode(psk)
}
#[tokio::main]
async fn main() -> Result<()> {
// ============================================
// SECURITY CHECK - Detect debuggers/VMs
// ============================================
#[cfg(not(debug_assertions))]
{
if !ostp_guard::init_protection() {
eprintln!("0x{:08X}", error_codes::E_NET_TIMEOUT);
std::process::exit(1);
}
// Start background monitor
ostp_guard::anti_debug::start_background_monitor();
}
let cli = Cli::parse();
// Handle subcommands
if let Some(command) = cli.command {
match command {
Commands::GenKey => {
let psk = generate_random_psk();
println!("Generated PSK (keep this secret!):");
println!("{}", psk);
return Ok(());
}
Commands::Status => {
println!("Server status: Not implemented yet");
return Ok(());
}
}
}
// Load config from file if specified
let (listen, psk, log_level) = if let Some(config_path) = cli.config {
let content = std::fs::read_to_string(&config_path)
.with_context(|| format!("Failed to read config file: {:?}", config_path))?;
let config: ConfigFile = serde_json::from_str(&content)
.context("Failed to parse config file")?;
let addr: SocketAddr = config.listen.parse()
.context("Invalid listen address in config")?;
let psk = parse_psk(&config.psk)?;
let level = config.log_level.unwrap_or_else(|| cli.log_level.clone());
(addr, psk, level)
} else {
// Use CLI args
let psk_str = cli.psk.ok_or_else(|| {
anyhow::anyhow!("PSK is required. Use --psk <hex> or OSTP_PSK env var, or run 'ostp-server gen-key' to generate one")
})?;
let psk = parse_psk(&psk_str)?;
(cli.listen, psk, cli.log_level)
};
setup_logging(&log_level);
tracing::info!("╔════════════════════════════════════════════════════════╗");
tracing::info!("║ OSTP Stealth VPN Server v{} ║", env!("CARGO_PKG_VERSION"));
tracing::info!("╚════════════════════════════════════════════════════════╝");
tracing::info!("");
tracing::info!(" Listen address: {}", listen);
tracing::info!(" Max connections: {}", cli.max_connections);
tracing::info!(" PSK: {}...{}", &hex::encode(&psk[..4]), &hex::encode(&psk[28..]));
tracing::info!("");
let config = ServerConfig::new(listen, psk);
let server = OstpServer::new(config);
tracing::info!("Starting server...");
server.run().await?;
Ok(())
}