Release v1.1.0

This commit is contained in:
thakares committed 2026-09-02 15:19:19 +05:30
1 parent 34227efd2b
commit edc710cbd2
46 files changed
+5324 -190

No files matched your search

@@ -0,0 +1,274 @@
//! Comprehensive test suite for third-party WireGuard Upstream .conf parsing and validation.
use nx9_wg_core::crypto::generate_keypair;
use nx9_wg_core::types::wireguard::InterfaceRole;
use nx9_wireguard::UpstreamConfigParser;
use uuid::Uuid;
#[test]
fn test_valid_proton_style_configuration() {
let (priv_k, pub_k) = generate_keypair();
let (_, peer_pub_k) = generate_keypair();
let conf = format!(
r#"
# ProtonVPN WireGuard Configuration
[Interface]
PrivateKey = {}
Address = 10.2.0.2/32
DNS = 10.2.0.1
MTU = 1420
[Peer]
# Server Node
PublicKey = {}
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = 37.19.199.155:51820
PersistentKeepalive = 25
"#,
priv_k.as_str(),
peer_pub_k.as_str()
);
let parsed = UpstreamConfigParser::parse(&conf, "proton0").expect("parse proton config");
assert_eq!(parsed.interface_name, "proton0");
assert_eq!(parsed.public_key.as_str(), pub_k.as_str());
assert_eq!(parsed.address_v4.to_string(), "10.2.0.2/32");
assert_eq!(parsed.address_v6, None);
assert_eq!(parsed.dns, Some("10.2.0.1".to_string()));
assert_eq!(parsed.mtu, Some(1420));
assert_eq!(parsed.listen_port, None);
assert_eq!(parsed.peer.name, "proton0-provider");
assert_eq!(parsed.peer.public_key.as_str(), peer_pub_k.as_str());
assert_eq!(parsed.peer.endpoint, "37.19.199.155:51820");
assert_eq!(parsed.peer.allowed_ips, "0.0.0.0/0, ::/0");
assert_eq!(parsed.peer.persistent_keepalive, Some(25));
assert_eq!(parsed.peer.preshared_key, None);
let iface_id = Uuid::new_v4();
let peer_id = Uuid::new_v4();
let (iface, peer) = parsed.into_desired_state(iface_id, peer_id);
assert_eq!(iface.id, iface_id);
assert_eq!(iface.name, "proton0");
assert_eq!(iface.role, InterfaceRole::Upstream);
assert_eq!(iface.listen_port, None);
assert!(iface.enabled);
assert_eq!(peer.id, peer_id);
assert_eq!(peer.interface_id, iface_id);
assert_eq!(peer.name, "proton0-provider");
assert_eq!(peer.allowed_ips, "0.0.0.0/0, ::/0");
assert_eq!(
peer.server_wireguard_allowed_ips_for_role(InterfaceRole::Upstream),
"0.0.0.0/0, ::/0"
);
}
#[test]
fn test_omitted_listen_port_remains_unspecified() {
let (priv_k, _) = generate_keypair();
let (_, peer_pub_k) = generate_keypair();
let conf = format!(
"[Interface]\nPrivateKey = {}\nAddress = 10.2.0.2/32\n[Peer]\nPublicKey = {}\nAllowedIPs = 0.0.0.0/0, ::/0\nEndpoint = 37.19.199.155:51820\n",
priv_k.as_str(),
peer_pub_k.as_str()
);
let parsed = UpstreamConfigParser::parse(&conf, "proton0").expect("parse config");
assert_eq!(parsed.listen_port, None);
assert_eq!(parsed.peer.endpoint, "37.19.199.155:51820");
}
#[test]
fn test_explicit_listen_port_is_preserved() {
let (priv_k, _) = generate_keypair();
let (_, peer_pub_k) = generate_keypair();
let conf = format!(
"[Interface]\nPrivateKey = {}\nAddress = 10.2.0.2/32\nListenPort = 45000\n[Peer]\nPublicKey = {}\nAllowedIPs = 0.0.0.0/0, ::/0\nEndpoint = 37.19.199.155:51820\n",
priv_k.as_str(),
peer_pub_k.as_str()
);
let parsed = UpstreamConfigParser::parse(&conf, "proton0").expect("parse config");
assert_eq!(parsed.listen_port, Some(45000));
}
#[test]
fn test_endpoint_port_is_not_local_listen_port() {
let (priv_k, _) = generate_keypair();
let (_, peer_pub_k) = generate_keypair();
let conf = format!(
"[Interface]\nPrivateKey = {}\nAddress = 10.2.0.2/32\n[Peer]\nPublicKey = {}\nAllowedIPs = 0.0.0.0/0, ::/0\nEndpoint = 37.19.199.155:51820\n",
priv_k.as_str(),
peer_pub_k.as_str()
);
let parsed = UpstreamConfigParser::parse(&conf, "proton0").expect("parse config");
assert_eq!(parsed.listen_port, None);
assert!(parsed.peer.endpoint.ends_with(":51820"));
}
#[test]
fn test_dual_stack_address_and_preshared_key() {
let (priv_k, _) = generate_keypair();
let (_, peer_pub_k) = generate_keypair();
let (psk, _) = generate_keypair();
let conf = format!(
r#"
[Interface]
PrivateKey = {}
Address = 10.2.0.2/32, fd00::2/64
DNS = 10.2.0.1, 1.1.1.1
[Peer]
PublicKey = {}
PresharedKey = {}
AllowedIPs = 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
Endpoint = vpn.example.com:51820
"#,
priv_k.as_str(),
peer_pub_k.as_str(),
psk.as_str()
);
let parsed = UpstreamConfigParser::parse(&conf, "vpn0").expect("parse dual stack");
assert_eq!(parsed.address_v4.to_string(), "10.2.0.2/32");
assert_eq!(
parsed.address_v6.map(|ip| ip.to_string()),
Some("fd00::2/64".to_string())
);
assert_eq!(parsed.dns, Some("10.2.0.1, 1.1.1.1".to_string()));
assert!(parsed.peer.preshared_key.is_some());
assert_eq!(parsed.peer.preshared_key.unwrap().as_str(), psk.as_str());
}
#[test]
fn test_reject_wg0_interface_name() {
let (priv_k, _) = generate_keypair();
let (_, peer_pub_k) = generate_keypair();
let conf = format!(
"[Interface]\nPrivateKey = {}\nAddress = 10.2.0.2/32\n[Peer]\nPublicKey = {}\nAllowedIPs = 0.0.0.0/0\nEndpoint = 1.2.3.4:51820\n",
priv_k.as_str(),
peer_pub_k.as_str()
);
let err = UpstreamConfigParser::parse(&conf, "wg0").unwrap_err();
assert!(err.to_string().contains("reserved name 'wg0'"));
}
#[test]
fn test_cardinality_rejections() {
let (priv_k, _) = generate_keypair();
let (_, peer_pub_k) = generate_keypair();
// 0 peers
let no_peers = format!(
"[Interface]\nPrivateKey = {}\nAddress = 10.2.0.2/32\n",
priv_k.as_str()
);
assert!(UpstreamConfigParser::parse(&no_peers, "proton0").is_err());
// 2 peers
let multi_peers = format!(
r#"
[Interface]
PrivateKey = {}
Address = 10.2.0.2/32
[Peer]
PublicKey = {}
AllowedIPs = 0.0.0.0/0
Endpoint = 1.2.3.4:51820
[Peer]
PublicKey = {}
AllowedIPs = 0.0.0.0/0
Endpoint = 5.6.7.8:51820
"#,
priv_k.as_str(),
peer_pub_k.as_str(),
peer_pub_k.as_str()
);
let err = UpstreamConfigParser::parse(&multi_peers, "proton0").unwrap_err();
assert!(err.to_string().contains("exactly one [Peer] section"));
// Missing [Interface]
let no_iface = format!(
"[Peer]\nPublicKey = {}\nAllowedIPs = 0.0.0.0/0\nEndpoint = 1.2.3.4:51820\n",
peer_pub_k.as_str()
);
assert!(UpstreamConfigParser::parse(&no_iface, "proton0").is_err());
}
#[test]
fn test_missing_and_malformed_fields_rejections() {
let (_, peer_pub_k) = generate_keypair();
// Missing PrivateKey
let no_priv = format!(
"[Interface]\nAddress = 10.2.0.2/32\n[Peer]\nPublicKey = {}\nAllowedIPs = 0.0.0.0/0\nEndpoint = 1.2.3.4:51820\n",
peer_pub_k.as_str()
);
assert!(UpstreamConfigParser::parse(&no_priv, "proton0").is_err());
// Malformed PrivateKey
let bad_priv = format!(
"[Interface]\nPrivateKey = not-a-key\nAddress = 10.2.0.2/32\n[Peer]\nPublicKey = {}\nAllowedIPs = 0.0.0.0/0\nEndpoint = 1.2.3.4:51820\n",
peer_pub_k.as_str()
);
assert!(UpstreamConfigParser::parse(&bad_priv, "proton0").is_err());
// Missing Address
let (priv_k, _) = generate_keypair();
let no_addr = format!(
"[Interface]\nPrivateKey = {}\n[Peer]\nPublicKey = {}\nAllowedIPs = 0.0.0.0/0\nEndpoint = 1.2.3.4:51820\n",
priv_k.as_str(),
peer_pub_k.as_str()
);
assert!(UpstreamConfigParser::parse(&no_addr, "proton0").is_err());
// Malformed Address
let bad_addr = format!(
"[Interface]\nPrivateKey = {}\nAddress = 999.999.999.999/99\n[Peer]\nPublicKey = {}\nAllowedIPs = 0.0.0.0/0\nEndpoint = 1.2.3.4:51820\n",
priv_k.as_str(),
peer_pub_k.as_str()
);
assert!(UpstreamConfigParser::parse(&bad_addr, "proton0").is_err());
// Missing PublicKey
let no_pub = format!(
"[Interface]\nPrivateKey = {}\nAddress = 10.2.0.2/32\n[Peer]\nAllowedIPs = 0.0.0.0/0\nEndpoint = 1.2.3.4:51820\n",
priv_k.as_str()
);
assert!(UpstreamConfigParser::parse(&no_pub, "proton0").is_err());
// Missing Endpoint
let no_ep = format!(
"[Interface]\nPrivateKey = {}\nAddress = 10.2.0.2/32\n[Peer]\nPublicKey = {}\nAllowedIPs = 0.0.0.0/0\n",
priv_k.as_str(),
peer_pub_k.as_str()
);
assert!(UpstreamConfigParser::parse(&no_ep, "proton0").is_err());
// Missing AllowedIPs
let no_aips = format!(
"[Interface]\nPrivateKey = {}\nAddress = 10.2.0.2/32\n[Peer]\nPublicKey = {}\nEndpoint = 1.2.3.4:51820\n",
priv_k.as_str(),
peer_pub_k.as_str()
);
assert!(UpstreamConfigParser::parse(&no_aips, "proton0").is_err());
// Unknown section
let unknown_sec = format!(
"[Interface]\nPrivateKey = {}\nAddress = 10.2.0.2/32\n[Unknown]\nKey = Val\n[Peer]\nPublicKey = {}\nAllowedIPs = 0.0.0.0/0\nEndpoint = 1.2.3.4:51820\n",
priv_k.as_str(),
peer_pub_k.as_str()
);
assert!(UpstreamConfigParser::parse(&unknown_sec, "proton0").is_err());
}