fix webrtc and login

This commit is contained in:
2026-09-24 13:55:59 +02:00
parent 5bac3174df
commit 844eaadee0
28 changed files with 628 additions and 43 deletions
+65
View File
@@ -0,0 +1,65 @@
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::time::Duration;
use tokio::net::{UdpSocket, lookup_host};
use tokio::time::timeout;
pub(super) async fn probe(url: &str, bind_ip: Ipv4Addr) -> anyhow::Result<SocketAddr> {
let endpoint = url.strip_prefix("stun:").ok_or_else(|| anyhow::anyhow!("URL STUN non prise en charge"))?;
let endpoint = endpoint.split('?').next().unwrap_or(endpoint);
let mut addresses = lookup_host(endpoint).await?;
let server = addresses.find(SocketAddr::is_ipv4).ok_or_else(|| anyhow::anyhow!("aucune adresse IPv4 pour le serveur STUN"))?;
let socket = UdpSocket::bind((bind_ip, 0)).await?;
let local = socket.local_addr()?;
let transaction = *uuid::Uuid::new_v4().as_bytes();
let mut request = [0u8; 20];
request[..2].copy_from_slice(&0x0001u16.to_be_bytes());
request[4..8].copy_from_slice(&0x2112a442u32.to_be_bytes());
request[8..20].copy_from_slice(&transaction[..12]);
tracing::info!(%server, %local, "Diagnostic STUN IPv4 : requête Binding envoyée (socket distinct d’ICE)");
socket.send_to(&request, server).await?;
let mut response = [0u8; 1500];
let (length, sender) = timeout(Duration::from_secs(5), socket.recv_from(&mut response)).await??;
anyhow::ensure!(sender == server, "réponse STUN d'une autre adresse : {sender}");
let mapped = mapped_address(&response[..length], &transaction[..12])?;
tracing::info!(%server, %local, %mapped, "Diagnostic STUN IPv4 : réponse Binding reçue");
Ok(mapped)
}
fn mapped_address(response: &[u8], transaction: &[u8]) -> anyhow::Result<SocketAddr> {
anyhow::ensure!(response.len() >= 20 && response[0..2] == [0x01, 0x01]
&& response[4..8] == 0x2112a442u32.to_be_bytes()
&& response[8..20] == *transaction, "réponse STUN invalide ou transaction différente");
let size = u16::from_be_bytes([response[2], response[3]]) as usize;
anyhow::ensure!(response.len() >= 20 + size, "réponse STUN tronquée");
let mut offset = 20;
while offset + 4 <= 20 + size {
let kind = u16::from_be_bytes([response[offset], response[offset + 1]]);
let len = u16::from_be_bytes([response[offset + 2], response[offset + 3]]) as usize;
offset += 4;
anyhow::ensure!(offset + len <= 20 + size, "attribut STUN tronqué");
if kind == 0x0020 && len >= 8 && response[offset + 1] == 1 {
let port = u16::from_be_bytes([response[offset + 2], response[offset + 3]]) ^ 0x2112;
let cookie = 0x2112a442u32.to_be_bytes();
let ip = Ipv4Addr::from(std::array::from_fn(|i| response[offset + 4 + i] ^ cookie[i]));
return Ok(SocketAddr::new(IpAddr::V4(ip), port));
}
offset += (len + 3) & !3;
}
anyhow::bail!("aucune adresse IPv4 XOR-MAPPED-ADDRESS dans la réponse STUN")
}
#[cfg(test)]
mod tests {
use super::mapped_address;
#[test]
fn decodes_ipv4_and_rejects_unrelated_response() {
let transaction = [7; 12];
let mut response = vec![0x01, 0x01, 0, 12, 0x21, 0x12, 0xa4, 0x42];
response.extend(transaction);
response.extend([0, 0x20, 0, 8, 0, 1, 0x3f, 0x52, 0x6a, 0x22, 0xa5, 0x43]);
assert_eq!(mapped_address(&response, &transaction).unwrap().to_string(), "75.48.1.1:7744");
assert!(mapped_address(&response, &[8; 12]).is_err());
assert!(mapped_address(&response[..25], &transaction).is_err());
}
}