feat: complete wgcloak v1 transports

This commit is contained in:
h3cx committed 2026-09-19 19:47:16 +02:00
1 parent 49ec9d8c33
commit cedab4910e
47 files changed
+2849 -400

No files matched your search

+118 -1
View File
@@ -248,6 +248,84 @@ async fn malformed_and_unauthenticated_packets_do_not_kill_server() {
server_task.abort();
}
#[tokio::test]
async fn direct_auth_attempt_limit_expires_and_recovers() {
let backend = UdpSocket::bind("127.0.0.1:0").await.unwrap();
let backend_addr = backend.local_addr().unwrap();
let (mut server_config, _) = configs(45790, backend_addr.port());
server_config.limits.max_auth_attempts_per_ip = 2;
server_config.limits.auth_attempt_window_secs = 1;
let server = DirectUdpServer::bind(server_config).await.unwrap();
let stats = server.stats();
let server_task = tokio::spawn(server.run());
let raw = UdpSocket::bind("127.0.0.1:0").await.unwrap();
let wrong_secret = [0xabu8; 32];
let mut response = [0u8; 2048];
for nonce_value in [1u8, 2] {
let mut nonce = [0u8; 16];
nonce[0] = nonce_value;
let hello = protocol::HelloPacket::authenticated(
&wrong_secret,
Bytes::from_static(b"test"),
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs(),
nonce,
)
.unwrap();
raw.send_to(&hello.encode().unwrap(), "127.0.0.1:45790")
.await
.unwrap();
let (len, _) = timeout(Duration::from_secs(2), raw.recv_from(&mut response))
.await
.unwrap()
.unwrap();
assert!(matches!(
protocol::parse_packet(&response[..len]),
Ok(protocol::Packet::Reject(protocol::RejectPacket {
reason: protocol::RejectReason::AuthenticationFailed,
..
}))
));
}
let mut limited_nonce = [0u8; 16];
limited_nonce[0] = 3;
let limited = protocol::HelloPacket::authenticated(
&wrong_secret,
Bytes::from_static(b"test"),
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs(),
limited_nonce,
)
.unwrap();
raw.send_to(&limited.encode().unwrap(), "127.0.0.1:45790")
.await
.unwrap();
let (len, _) = timeout(Duration::from_secs(2), raw.recv_from(&mut response))
.await
.unwrap()
.unwrap();
assert!(matches!(
protocol::parse_packet(&response[..len]),
Ok(protocol::Packet::Reject(protocol::RejectPacket {
reason: protocol::RejectReason::RateLimited,
..
}))
));
tokio::time::sleep(Duration::from_millis(1_100)).await;
let client_config = configs(45790, backend_addr.port()).1;
let session = DirectUdpSession::connect(&client_config).await.unwrap();
assert!(stats.snapshot().rate_limited_attempts >= 1);
session.close().await.unwrap();
server_task.abort();
}
#[tokio::test]
async fn authenticated_source_port_change_updates_return_peer() {
let backend = UdpSocket::bind("127.0.0.1:0").await.unwrap();
@@ -320,7 +398,9 @@ async fn authenticated_source_port_change_updates_return_peer() {
async fn identical_hello_retransmission_recovers_original_accept_and_session() {
let backend = UdpSocket::bind("127.0.0.1:0").await.unwrap();
let backend_addr = backend.local_addr().unwrap();
let (server_config, _) = configs(45788, backend_addr.port());
let (mut server_config, _) = configs(45788, backend_addr.port());
// The cached exact retry must not consume a second auth-attempt slot.
server_config.limits.max_auth_attempts_per_ip = 1;
let server = DirectUdpServer::bind(server_config).await.unwrap();
let observer = server.handle();
let server_task = tokio::spawn(server.run());
@@ -481,6 +561,43 @@ async fn identical_hello_retransmission_recovers_original_accept_and_session() {
server_task.abort();
}
#[tokio::test]
async fn direct_udp_supports_ipv6_loopback_listen() {
let probe = match UdpSocket::bind("[::1]:0").await {
Ok(socket) => socket,
Err(_) => return,
};
let port = probe.local_addr().unwrap().port();
drop(probe);
let backend = UdpSocket::bind("127.0.0.1:0").await.unwrap();
let backend_addr = backend.local_addr().unwrap();
let (mut server_config, mut client_config) = configs(port, backend_addr.port());
server_config.server.listen = "::1".to_owned();
client_config.client.server = "::1".to_owned();
let server = DirectUdpServer::bind(server_config).await.unwrap();
let server_task = tokio::spawn(server.run());
let backend_task = tokio::spawn(async move {
let mut buffer = [0u8; 2048];
let (len, peer) = backend.recv_from(&mut buffer).await.unwrap();
backend.send_to(&buffer[..len], peer).await.unwrap();
});
let session = DirectUdpSession::connect(&client_config).await.unwrap();
session
.send_datagram(Bytes::from_static(b"ipv6"))
.await
.unwrap();
assert_eq!(
timeout(Duration::from_secs(2), session.recv_datagram())
.await
.unwrap()
.unwrap(),
Bytes::from_static(b"ipv6")
);
session.close().await.unwrap();
backend_task.await.unwrap();
server_task.abort();
}
#[tokio::test]
async fn flags_are_authenticated_and_invalid_close_cannot_remove_session() {
let backend = UdpSocket::bind("127.0.0.1:0").await.unwrap();