Skip to main content

aivpn_server/
server.rs

1//! AIVPN Server
2//!
3//! Main server entry point
4
5use tracing_subscriber::{self, EnvFilter};
6
7use clap::Parser;
8
9use crate::gateway::{Gateway, GatewayConfig};
10use aivpn_common::error::Result;
11
12/// AIVPN Server - Censorship-resistant VPN gateway
13#[derive(Parser, Debug)]
14#[command(author, version, about, long_about = None)]
15pub struct ServerArgs {
16    /// Listen address
17    #[arg(short, long, default_value = "0.0.0.0:443")]
18    pub listen: String,
19
20    /// TUN device name (random if not specified — avoids fingerprinting)
21    #[arg(long)]
22    pub tun_name: Option<String>,
23
24    /// Path to 32-byte server private key file
25    #[arg(long)]
26    pub key_file: Option<String>,
27
28    /// Config file path
29    #[arg(short, long)]
30    pub config: Option<String>,
31
32    /// Path to clients database file
33    #[arg(long, default_value = "/etc/aivpn/clients.json")]
34    pub clients_db: String,
35
36    /// Add a new client with the given name and print config
37    #[arg(long, value_name = "NAME")]
38    pub add_client: Option<String>,
39
40    /// Remove a client by ID
41    #[arg(long, value_name = "ID")]
42    pub remove_client: Option<String>,
43
44    /// List all registered clients with stats
45    #[arg(long)]
46    pub list_clients: bool,
47
48    /// Show client config by ID (for QR / import)
49    #[arg(long, value_name = "ID")]
50    pub show_client: Option<String>,
51
52    /// Public IP of this server (embedded into connection keys).
53    /// Required when using --add-client or --show-client to generate connection keys.
54    #[arg(long, env = "AIVPN_SERVER_IP")]
55    pub server_ip: Option<String>,
56
57    /// Per-IP packet rate limit for incoming UDP traffic.
58    #[arg(long, env = "AIVPN_PER_IP_PPS_LIMIT", default_value_t = 50000)]
59    pub per_ip_pps_limit: u64,
60
61    /// Directory for mask file storage.
62    /// Resolved in order: CLI flag → env AIVPN_MASK_DIR → server.json "mask_dir" → default.
63    #[arg(long, env = "AIVPN_MASK_DIR")]
64    pub mask_dir: Option<String>,
65
66    /// Unix socket path for the management HTTP API.
67    /// If not specified, the management API is disabled.
68    /// Example: /run/aivpn/api.sock
69    #[cfg(all(feature = "management-api", unix))]
70    #[arg(long, env = "AIVPN_MANAGEMENT_SOCKET")]
71    pub management_socket: Option<String>,
72}
73
74/// AIVPN Server instance
75pub struct AivpnServer {
76    gateway: Gateway,
77}
78
79impl AivpnServer {
80    /// Create new server instance
81    pub fn new(config: GatewayConfig) -> Result<Self> {
82        let gateway = Gateway::new(config)?;
83        Ok(Self { gateway })
84    }
85
86    /// Run the server
87    pub async fn run(self) -> Result<()> {
88        self.gateway.run().await
89    }
90}
91
92/// Initialize logging
93pub fn init_logging() {
94    tracing_subscriber::fmt()
95        .with_env_filter(
96            EnvFilter::from_default_env()
97                .add_directive("aivpn_server=debug".parse().unwrap())
98                .add_directive("aivpn_common=debug".parse().unwrap()),
99        )
100        .init();
101}
102
103#[cfg(test)]
104mod tests {
105    use super::*;
106
107    #[test]
108    fn test_server_creation() {
109        // Create temp mask dir with a preset mask for the test
110        let mask_dir = std::path::PathBuf::from("/tmp/aivpn-test-server-masks");
111        let _ = std::fs::create_dir_all(&mask_dir);
112        let mask = aivpn_common::mask::preset_masks::webrtc_zoom_v3();
113        let json = serde_json::to_string_pretty(&mask).unwrap();
114        std::fs::write(mask_dir.join(format!("{}.json", mask.mask_id)), &json).unwrap();
115        std::fs::write(mask_dir.join(format!("{}.stats", mask.mask_id)), "{}").unwrap();
116
117        let mut config = GatewayConfig::default();
118        config.mask_dir = mask_dir;
119        let server = AivpnServer::new(config);
120        assert!(server.is_ok());
121    }
122}