release: NX9-WG v1.0.0

This commit is contained in:
thakares committed 2026-08-18 17:32:56 +05:30
1 parent c8a9b7cde6
commit 4dfe42fe68
42 files changed
+4689 -336

No files matched your search

+65 -12
View File
@@ -23,9 +23,11 @@ use nx9_wg_core::validation::{
validate_port_spec,
};
use nx9_wg_db::Store;
#[allow(unused_imports)]
use nx9_wg_network::{
IpForwardingStatus, NativeLinuxNetworkEngine, NetworkEngine, SimulatedNetworkEngine,
};
#[allow(unused_imports)]
use nx9_wireguard::{
ClientConfigBuilder, NativeLinuxWireGuardEngine, SimulatedWireGuardEngine, WireGuardEngine,
generate_qr_ascii, generate_qr_png_bytes, generate_qr_svg,
@@ -509,6 +511,8 @@ enum PeerSubcommands {
mtu: Option<u16>,
#[arg(long, help = "Explicit client profile ID")]
profile: Option<String>,
#[arg(long, help = "WireGuard server endpoint host or IP")]
endpoint: Option<String>,
#[arg(short, long, help = "Write configuration to file")]
output: Option<PathBuf>,
},
@@ -533,6 +537,8 @@ enum PeerSubcommands {
mtu: Option<u16>,
#[arg(long, help = "Explicit client profile ID")]
profile: Option<String>,
#[arg(long, help = "WireGuard server endpoint host or IP")]
endpoint: Option<String>,
#[arg(
long = "qr-format",
default_value = "terminal",
@@ -932,6 +938,28 @@ enum LivePeerSubcommands {
Show { id: String },
}
fn create_wireguard_engine() -> Arc<dyn WireGuardEngine> {
#[cfg(target_os = "linux")]
{
Arc::new(NativeLinuxWireGuardEngine::new())
}
#[cfg(not(target_os = "linux"))]
{
Arc::new(SimulatedWireGuardEngine::new())
}
}
fn create_network_engine() -> Arc<dyn NetworkEngine> {
#[cfg(target_os = "linux")]
{
Arc::new(NativeLinuxNetworkEngine::new())
}
#[cfg(not(target_os = "linux"))]
{
Arc::new(SimulatedNetworkEngine::new())
}
}
// ── Output Formatter ────────────────────────────────────────────────────────
fn print_output<T: Serialize>(
@@ -1712,7 +1740,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Interface '{interface}' disabled.");
}
InterfaceSubcommands::Status { interface } => {
let wg = SimulatedWireGuardEngine::new();
let wg = create_wireguard_engine();
let stats = wg.get_interface_stats(&interface).await?;
match stats {
Some(s) => print_output(&s, format)?,
@@ -1721,8 +1749,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
InterfaceSubcommands::Reconcile { interface: _ } => {
let state = AppState::new(store);
let wg = Arc::new(SimulatedWireGuardEngine::new());
let net = Arc::new(SimulatedNetworkEngine::new());
let wg = create_wireguard_engine();
let net = create_network_engine();
let reconciler = ReconciliationEngine::new(state, wg, net);
let report = reconciler.apply().await?;
print_output(&report, format)?;
@@ -1988,7 +2016,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.get_interface(peer.interface_id)
.await?
.ok_or("Interface not found")?;
let wg = SimulatedWireGuardEngine::new();
let wg = create_wireguard_engine();
let iface_stats = wg.get_interface_stats(&iface.name).await?;
let peer_stat = iface_stats.and_then(|s| {
s.peers
@@ -2008,6 +2036,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
nat,
mtu,
profile,
endpoint,
output,
} => {
let peer_id = Uuid::parse_str(&id)?;
@@ -2060,10 +2089,20 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
None
};
let server_host = if let Some(ref ep) = endpoint {
ep.trim().to_string()
} else if let Some(s) = store.get_setting("server_endpoint").await? {
s.value.trim().to_string()
} else if let Some(s) = store.get_setting("public_endpoint").await? {
s.value.trim().to_string()
} else {
return Err("No reachable WireGuard server endpoint is configured. Configure 'server_endpoint' in settings or provide --endpoint.".into());
};
let conf = ClientConfigBuilder::build_with_profile(
&peer,
&iface,
"127.0.0.1",
&server_host,
resolved_profile.as_ref(),
)?;
if let Some(out_path) = output {
@@ -2081,6 +2120,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
nat,
mtu,
profile,
endpoint,
qr_format,
} => {
let peer_id = Uuid::parse_str(&id)?;
@@ -2133,10 +2173,20 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
None
};
let server_host = if let Some(ref ep) = endpoint {
ep.trim().to_string()
} else if let Some(s) = store.get_setting("server_endpoint").await? {
s.value.trim().to_string()
} else if let Some(s) = store.get_setting("public_endpoint").await? {
s.value.trim().to_string()
} else {
return Err("No reachable WireGuard server endpoint is configured. Configure 'server_endpoint' in settings or provide --endpoint.".into());
};
let conf = ClientConfigBuilder::build_with_profile(
&peer,
&iface,
"127.0.0.1",
&server_host,
resolved_profile.as_ref(),
)?;
match qr_format.to_lowercase().as_str() {
@@ -2778,12 +2828,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Commands::Live(args) => match args.subcommand {
LiveSubcommands::Interface(i_args) => match i_args.subcommand {
LiveInterfaceSubcommands::List => {
let wg = SimulatedWireGuardEngine::new();
let wg = create_wireguard_engine();
let list = wg.list_interfaces().await?;
print_output(&list, format)?;
}
LiveInterfaceSubcommands::Show { name } => {
let wg = SimulatedWireGuardEngine::new();
let wg = create_wireguard_engine();
let stats = wg.get_interface_stats(&name).await?;
match stats {
Some(s) => print_output(&s, format)?,
@@ -2796,13 +2846,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
},
LiveSubcommands::Peer(p_args) => match p_args.subcommand {
LivePeerSubcommands::List { interface } => {
let wg = SimulatedWireGuardEngine::new();
let wg = create_wireguard_engine();
let stats = wg.get_interface_stats(&interface).await?;
let peers = stats.map(|s| s.peers).unwrap_or_default();
print_output(&peers, format)?;
}
LivePeerSubcommands::Show { id } => {
let wg = SimulatedWireGuardEngine::new();
let wg = create_wireguard_engine();
let ifaces = wg.list_interfaces().await?;
let mut found = None;
for iface in ifaces {
@@ -2835,7 +2885,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
print_output(&status, format)?;
}
LiveSubcommands::Firewall => {
let net = NativeLinuxNetworkEngine::new();
let net = create_network_engine();
let ruleset = net.get_active_nftables_ruleset().await?;
print_output(&ruleset, format)?;
}
@@ -2844,8 +2894,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
print_output(&status, format)?;
}
LiveSubcommands::Nat => {
let net = create_network_engine();
let ruleset = net.get_active_nftables_ruleset().await.unwrap_or_default();
let nat_active = ruleset.contains("masquerade");
let status = serde_json::json!({
"nat_active": true,
"nat_masquerade_active": nat_active,
"table": "inet nx9_wg",
"chain": "postrouting"
});