65 lines
2.2 KiB
Rust
65 lines
2.2 KiB
Rust
use bytes::BytesMut;
|
|
use std::net::SocketAddr;
|
|
use tokio::net::UdpSocket;
|
|
use niom_turn::constants::*;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> anyhow::Result<()> {
|
|
tracing_subscriber::fmt::init();
|
|
let server: SocketAddr = "127.0.0.1:3478".parse()?;
|
|
let local = UdpSocket::bind("0.0.0.0:0").await?;
|
|
|
|
// Build a minimal STUN Binding Request with USERNAME and placeholder MESSAGE-INTEGRITY
|
|
let username = "testuser";
|
|
let password = "secretpassword"; // matches server's in-memory creds
|
|
|
|
let mut buf = BytesMut::new();
|
|
buf.extend_from_slice(&METHOD_BINDING.to_be_bytes()); // Binding Request
|
|
buf.extend_from_slice(&0u16.to_be_bytes()); // length placeholder
|
|
buf.extend_from_slice(&MAGIC_COOKIE_U32.to_be_bytes());
|
|
let trans = [7u8; 12];
|
|
buf.extend_from_slice(&trans);
|
|
|
|
// USERNAME
|
|
let uname = username.as_bytes();
|
|
buf.extend_from_slice(&ATTR_USERNAME.to_be_bytes());
|
|
buf.extend_from_slice(&(uname.len() as u16).to_be_bytes());
|
|
buf.extend_from_slice(uname);
|
|
while (buf.len() % 4) != 0 { buf.extend_from_slice(&[0u8]); }
|
|
|
|
// MESSAGE-INTEGRITY placeholder
|
|
let mi_attr_offset = buf.len();
|
|
buf.extend_from_slice(&ATTR_MESSAGE_INTEGRITY.to_be_bytes());
|
|
buf.extend_from_slice(&(20u16).to_be_bytes());
|
|
let mi_val_pos = buf.len();
|
|
buf.extend_from_slice(&[0u8;20]);
|
|
while (buf.len() % 4) != 0 { buf.extend_from_slice(&[0u8]); }
|
|
|
|
// fix length
|
|
let total_len = (buf.len() - 20) as u16;
|
|
let len_bytes = total_len.to_be_bytes();
|
|
buf[2] = len_bytes[0];
|
|
buf[3] = len_bytes[1];
|
|
|
|
// compute HMAC over bytes up to MI attribute header
|
|
{
|
|
use hmac::{Hmac, Mac};
|
|
use sha1::Sha1;
|
|
type HmacSha1 = Hmac<Sha1>;
|
|
let mut mac = HmacSha1::new_from_slice(password.as_bytes()).expect("HMAC key");
|
|
mac.update(&buf[..mi_attr_offset]);
|
|
let res = mac.finalize().into_bytes();
|
|
for i in 0..20 { buf[mi_val_pos + i] = res[i]; }
|
|
}
|
|
|
|
// send
|
|
local.send_to(&buf, server).await?;
|
|
|
|
let mut r = vec![0u8; 1500];
|
|
let (len, addr) = local.recv_from(&mut r).await?;
|
|
println!("got {} bytes from {}", len, addr);
|
|
// dump hex
|
|
println!("{:02x?}", &r[..len]);
|
|
Ok(())
|
|
}
|