1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
78use std::time::Duration;
79
80use hmac::{Hmac, Mac};
81use md5::{Digest as Md5Digest, Md5};
82use sha1::Sha1;
83
84use crate::nat_punch::STUN_MAGIC_COOKIE;
85use crate::udp_sockets;
86
87pub mod msg_type {
89 pub const ALLOCATE_REQUEST: u16 = 0x0003;
91 pub const ALLOCATE_SUCCESS: u16 = 0x0103;
93 pub const ALLOCATE_ERROR: u16 = 0x0113;
95 pub const REFRESH_REQUEST: u16 = 0x0004;
97 pub const REFRESH_SUCCESS: u16 = 0x0104;
99 pub const CREATE_PERMISSION_REQUEST: u16 = 0x0008;
101 pub const CREATE_PERMISSION_SUCCESS: u16 = 0x0108;
103 pub const SEND_INDICATION: u16 = 0x0016;
105 pub const DATA_INDICATION: u16 = 0x0017;
107}
108
109pub mod attr {
111 pub const MAPPED_ADDRESS: u16 = 0x0001;
113 pub const USERNAME: u16 = 0x0006;
115 pub const MESSAGE_INTEGRITY: u16 = 0x0008;
117 pub const ERROR_CODE: u16 = 0x0009;
119 pub const REALM: u16 = 0x0014;
121 pub const NONCE: u16 = 0x0015;
123 pub const XOR_MAPPED_ADDRESS: u16 = 0x0020;
125 pub const XOR_PEER_ADDRESS: u16 = 0x0012;
127 pub const XOR_RELAYED_ADDRESS: u16 = 0x0016;
129 pub const DATA: u16 = 0x0013;
131 pub const LIFETIME: u16 = 0x000d;
133 pub const REQUESTED_TRANSPORT: u16 = 0x0019;
135}
136
137#[derive(Debug, Clone)]
140pub struct TurnAllocation {
141 pub socket_id: u64,
143 pub server: std::net::SocketAddr,
145 pub username: String,
147 pub password: String,
149 pub realm: String,
151 pub nonce: Vec<u8>,
153 pub relay_ip: IpAddr,
155 pub relay_port: u16,
157 pub lifetime_secs: u32,
159}
160
161fn fresh_tx_id() -> [u8; 12] {
167 use std::sync::atomic::{AtomicU64, Ordering};
168 static COUNTER: AtomicU64 = AtomicU64::new(0);
169
170 let mut id = [0u8; 12];
171 let nanos = std::time::SystemTime::now()
172 .duration_since(std::time::UNIX_EPOCH)
173 .map(|d| d.as_nanos())
174 .unwrap_or(0);
175 let counter = COUNTER.fetch_add(1, Ordering::Relaxed);
176 id[0..8].copy_from_slice(&(nanos as u64).to_le_bytes());
177 id[8..12].copy_from_slice(&(counter as u32).to_le_bytes());
178 let pid = std::process::id();
179 let pid_be = pid.to_le_bytes();
180 for i in 0..4 {
181 id[i] ^= pid_be[i];
182 }
183 id
184}
185
186fn long_term_key(username: &str, realm: &str, password: &str) -> [u8; 16] {
188 let mut h = Md5::new();
189 h.update(username.as_bytes());
190 h.update(b":");
191 h.update(realm.as_bytes());
192 h.update(b":");
193 h.update(password.as_bytes());
194 let result = h.finalize();
195 let mut out = [0u8; 16];
196 out.copy_from_slice(&result);
197 out
198}
199
200fn hmac_sha1(key: &[u8], msg_prefix: &[u8]) -> [u8; 20] {
203 type HmacSha1 = Hmac<Sha1>;
204 let mut mac = HmacSha1::new_from_slice(key).expect("hmac key length");
205 mac.update(msg_prefix);
206 let result = mac.finalize().into_bytes();
207 let mut out = [0u8; 20];
208 out.copy_from_slice(&result);
209 out
210}
211
212#[inline]
214fn pad4(n: usize) -> usize {
215 (n + 3) & !3
216}
217
218pub fn push_attr(buf: &mut Vec<u8>, attr_type: u16, value: &[u8]) -> usize {
221 buf.extend_from_slice(&attr_type.to_be_bytes());
222 buf.extend_from_slice(&(value.len() as u16).to_be_bytes());
223 buf.extend_from_slice(value);
224 let pad = pad4(value.len()) - value.len();
225 for _ in 0..pad {
226 buf.push(0);
227 }
228 4 + pad4(value.len())
229}
230
231pub fn push_xor_addr_attr(
235 buf: &mut Vec<u8>,
236 attr_type: u16,
237 ip: IpAddr,
238 port: u16,
239 tx_id: &[u8; 12],
240) -> usize {
241 let xor_port = port ^ ((STUN_MAGIC_COOKIE >> 16) as u16);
242 let mut val: Vec<u8> = Vec::new();
243 val.push(0); match ip {
245 IpAddr::V4(v4) => {
246 val.push(0x01); val.extend_from_slice(&xor_port.to_be_bytes());
248 let xor_addr = u32::from_be_bytes(v4.octets()) ^ STUN_MAGIC_COOKIE;
249 val.extend_from_slice(&xor_addr.to_be_bytes());
250 }
251 IpAddr::V6(v6) => {
252 val.push(0x02); val.extend_from_slice(&xor_port.to_be_bytes());
254 let mut octets = v6.octets();
255 let cookie_be = STUN_MAGIC_COOKIE.to_be_bytes();
256 for i in 0..4 {
257 octets[i] ^= cookie_be[i];
258 }
259 for i in 0..12 {
260 octets[4 + i] ^= tx_id[i];
261 }
262 val.extend_from_slice(&octets);
263 }
264 }
265 push_attr(buf, attr_type, &val)
266}
267
268pub fn parse_xor_addr(value: &[u8], tx_id: &[u8; 12]) -> Option<(IpAddr, u16)> {
271 if value.len() < 8 {
272 return None;
273 }
274 let family = value[1];
275 let xor_port = u16::from_be_bytes([value[2], value[3]]);
276 let port = xor_port ^ ((STUN_MAGIC_COOKIE >> 16) as u16);
277 match family {
278 0x01 => {
279 let xor_addr = u32::from_be_bytes([value[4], value[5], value[6], value[7]]);
280 let addr = xor_addr ^ STUN_MAGIC_COOKIE;
281 Some((IpAddr::V4(Ipv4Addr::from(addr.to_be_bytes())), port))
282 }
283 0x02 if value.len() >= 20 => {
284 let mut octets = [0u8; 16];
285 octets.copy_from_slice(&value[4..20]);
286 let cookie_be = STUN_MAGIC_COOKIE.to_be_bytes();
287 for i in 0..4 {
288 octets[i] ^= cookie_be[i];
289 }
290 for i in 0..12 {
291 octets[4 + i] ^= tx_id[i];
292 }
293 Some((IpAddr::V6(Ipv6Addr::from(octets)), port))
294 }
295 _ => None,
296 }
297}
298
299pub fn build_message(msg_type: u16, tx_id: &[u8; 12], attrs: &[u8]) -> Vec<u8> {
303 let mut buf = Vec::with_capacity(20 + attrs.len());
304 buf.extend_from_slice(&msg_type.to_be_bytes());
305 buf.extend_from_slice(&(attrs.len() as u16).to_be_bytes());
306 buf.extend_from_slice(&STUN_MAGIC_COOKIE.to_be_bytes());
307 buf.extend_from_slice(tx_id);
308 buf.extend_from_slice(attrs);
309 buf
310}
311
312fn append_message_integrity(msg: &mut Vec<u8>, key: &[u8]) {
319 let attrs_len = (msg.len() - 20) as u16;
321 let length_with_mi = attrs_len + 24;
322 msg[2..4].copy_from_slice(&length_with_mi.to_be_bytes());
323 let hmac = hmac_sha1(key, msg);
325 msg.extend_from_slice(&attr::MESSAGE_INTEGRITY.to_be_bytes());
326 msg.extend_from_slice(&20u16.to_be_bytes());
327 msg.extend_from_slice(&hmac);
328}
329
330fn iter_attrs(pkt: &[u8]) -> impl Iterator<Item = (u16, &[u8])> {
333 let msg_len = if pkt.len() >= 4 {
334 u16::from_be_bytes([pkt[2], pkt[3]]) as usize
335 } else {
336 0
337 };
338 let body_end = 20 + msg_len;
339 let body_end = body_end.min(pkt.len());
340 let mut off = 20;
341 std::iter::from_fn(move || {
342 if off + 4 > body_end {
343 return None;
344 }
345 let attr_type = u16::from_be_bytes([pkt[off], pkt[off + 1]]);
346 let attr_len = u16::from_be_bytes([pkt[off + 2], pkt[off + 3]]) as usize;
347 let val_start = off + 4;
348 let val_end = val_start + attr_len;
349 if val_end > body_end {
350 return None;
351 }
352 let val = &pkt[val_start..val_end];
353 off = val_end;
354 if off % 4 != 0 {
355 off += 4 - (off % 4);
356 }
357 Some((attr_type, val))
358 })
359}
360
361pub fn message_type(pkt: &[u8]) -> u16 {
364 if pkt.len() < 2 {
365 0
366 } else {
367 u16::from_be_bytes([pkt[0], pkt[1]])
368 }
369}
370
371pub fn build_allocate_request_unauth(tx_id: &[u8; 12]) -> Vec<u8> {
374 let mut attrs = Vec::new();
375 push_attr(&mut attrs, attr::REQUESTED_TRANSPORT, &[17, 0, 0, 0]);
377 build_message(msg_type::ALLOCATE_REQUEST, tx_id, &attrs)
378}
379
380pub fn build_allocate_request_auth(
383 tx_id: &[u8; 12],
384 username: &str,
385 realm: &str,
386 password: &str,
387 nonce: &[u8],
388) -> Vec<u8> {
389 let mut attrs = Vec::new();
390 push_attr(&mut attrs, attr::REQUESTED_TRANSPORT, &[17, 0, 0, 0]);
391 push_attr(&mut attrs, attr::USERNAME, username.as_bytes());
392 push_attr(&mut attrs, attr::REALM, realm.as_bytes());
393 push_attr(&mut attrs, attr::NONCE, nonce);
394 push_attr(&mut attrs, attr::LIFETIME, &600u32.to_be_bytes());
396 let mut msg = build_message(msg_type::ALLOCATE_REQUEST, tx_id, &attrs);
397 let key = long_term_key(username, realm, password);
398 append_message_integrity(&mut msg, &key);
399 msg
400}
401
402pub fn parse_allocate_401(pkt: &[u8]) -> Option<(String, Vec<u8>)> {
404 if message_type(pkt) != msg_type::ALLOCATE_ERROR {
405 return None;
406 }
407 let mut realm: Option<String> = None;
408 let mut nonce: Option<Vec<u8>> = None;
409 let mut code_401 = false;
410 for (t, v) in iter_attrs(pkt) {
411 match t {
412 attr::ERROR_CODE if v.len() >= 4 => {
413 let code = (v[2] as u16) * 100 + (v[3] as u16);
415 if code == 401 {
416 code_401 = true;
417 }
418 }
419 attr::REALM => {
420 realm = std::str::from_utf8(v).ok().map(|s| s.to_string());
421 }
422 attr::NONCE => {
423 nonce = Some(v.to_vec());
424 }
425 _ => {}
426 }
427 }
428 if code_401 {
429 match (realm, nonce) {
430 (Some(r), Some(n)) => Some((r, n)),
431 _ => None,
432 }
433 } else {
434 None
435 }
436}
437
438pub fn parse_allocate_success(pkt: &[u8]) -> Option<(IpAddr, u16, u32)> {
441 if message_type(pkt) != msg_type::ALLOCATE_SUCCESS {
442 return None;
443 }
444 if pkt.len() < 20 {
445 return None;
446 }
447 let mut tx_id = [0u8; 12];
448 tx_id.copy_from_slice(&pkt[8..20]);
449 let mut relay: Option<(IpAddr, u16)> = None;
450 let mut lifetime: u32 = 600;
451 for (t, v) in iter_attrs(pkt) {
452 match t {
453 attr::XOR_RELAYED_ADDRESS => {
454 relay = parse_xor_addr(v, &tx_id);
455 }
456 attr::LIFETIME if v.len() >= 4 => {
457 lifetime = u32::from_be_bytes([v[0], v[1], v[2], v[3]]);
458 }
459 _ => {}
460 }
461 }
462 relay.map(|(ip, port)| (ip, port, lifetime))
463}
464
465pub fn allocate(
468 socket_id: u64,
469 server_host: &str,
470 server_port: u16,
471 username: &str,
472 password: &str,
473 timeout: Duration,
474) -> Option<TurnAllocation> {
475 let server = udp_sockets::resolve_one(server_host, server_port)?;
476 let socket = udp_sockets::get(socket_id)?;
477
478 let tx1 = fresh_tx_id();
480 let req1 = build_allocate_request_unauth(&tx1);
481 socket.send_to(&req1, server).ok()?;
482 socket.set_read_timeout(Some(timeout)).ok()?;
483 let mut buf = [0u8; 2048];
484 let (realm, nonce) = loop {
485 let (n, src) = socket.recv_from(&mut buf).ok()?;
486 if src != server {
487 continue;
488 }
489 if n < 20 || buf[8..20] != tx1 {
490 continue;
491 }
492 match parse_allocate_401(&buf[..n]) {
493 Some(rn) => break rn,
494 None => return None,
495 }
496 };
497
498 let tx2 = fresh_tx_id();
500 let req2 = build_allocate_request_auth(&tx2, username, realm.as_str(), password, &nonce);
501 socket.send_to(&req2, server).ok()?;
502 socket.set_read_timeout(Some(timeout)).ok()?;
503 let (relay_ip, relay_port, lifetime) = loop {
504 let (n, src) = socket.recv_from(&mut buf).ok()?;
505 if src != server {
506 continue;
507 }
508 if n < 20 || buf[8..20] != tx2 {
509 continue;
510 }
511 match parse_allocate_success(&buf[..n]) {
512 Some(r) => break r,
513 None => return None,
514 }
515 };
516
517 Some(TurnAllocation {
518 socket_id,
519 server,
520 username: username.to_string(),
521 password: password.to_string(),
522 realm,
523 nonce,
524 relay_ip,
525 relay_port,
526 lifetime_secs: lifetime,
527 })
528}
529
530pub fn build_create_permission(
533 tx_id: &[u8; 12],
534 peer_ip: IpAddr,
535 allocation: &TurnAllocation,
536) -> Vec<u8> {
537 let mut attrs = Vec::new();
538 push_xor_addr_attr(&mut attrs, attr::XOR_PEER_ADDRESS, peer_ip, 0, tx_id);
539 push_attr(&mut attrs, attr::USERNAME, allocation.username.as_bytes());
540 push_attr(&mut attrs, attr::REALM, allocation.realm.as_bytes());
541 push_attr(&mut attrs, attr::NONCE, &allocation.nonce);
542 let mut msg = build_message(msg_type::CREATE_PERMISSION_REQUEST, tx_id, &attrs);
543 let key = long_term_key(
544 &allocation.username,
545 &allocation.realm,
546 &allocation.password,
547 );
548 append_message_integrity(&mut msg, &key);
549 msg
550}
551
552pub fn create_permission(allocation: &TurnAllocation, peer_ip: IpAddr, timeout: Duration) -> bool {
556 let Some(socket) = udp_sockets::get(allocation.socket_id) else {
557 return false;
558 };
559 let tx_id = fresh_tx_id();
560 let req = build_create_permission(&tx_id, peer_ip, allocation);
561 if socket.send_to(&req, allocation.server).is_err() {
562 return false;
563 }
564 if socket.set_read_timeout(Some(timeout)).is_err() {
565 return false;
566 }
567 let mut buf = [0u8; 2048];
568 loop {
569 let (n, src) = match socket.recv_from(&mut buf) {
570 Ok(p) => p,
571 Err(_) => return false,
572 };
573 if src != allocation.server {
574 continue;
575 }
576 if n < 20 || buf[8..20] != tx_id {
577 continue;
578 }
579 return message_type(&buf[..n]) == msg_type::CREATE_PERMISSION_SUCCESS;
580 }
581}
582
583pub fn build_send_indication(
586 tx_id: &[u8; 12],
587 peer_ip: IpAddr,
588 peer_port: u16,
589 payload: &[u8],
590) -> Vec<u8> {
591 let mut attrs = Vec::new();
592 push_xor_addr_attr(
593 &mut attrs,
594 attr::XOR_PEER_ADDRESS,
595 peer_ip,
596 peer_port,
597 tx_id,
598 );
599 push_attr(&mut attrs, attr::DATA, payload);
600 build_message(msg_type::SEND_INDICATION, tx_id, &attrs)
601}
602
603pub fn send_to_peer(
608 allocation: &TurnAllocation,
609 peer_ip: IpAddr,
610 peer_port: u16,
611 payload: &[u8],
612) -> Option<usize> {
613 let socket = udp_sockets::get(allocation.socket_id)?;
614 let tx_id = fresh_tx_id();
615 let msg = build_send_indication(&tx_id, peer_ip, peer_port, payload);
616 socket.send_to(&msg, allocation.server).ok()
617}
618
619pub fn parse_data_indication(pkt: &[u8]) -> Option<(IpAddr, u16, Vec<u8>)> {
621 if message_type(pkt) != msg_type::DATA_INDICATION {
622 return None;
623 }
624 if pkt.len() < 20 {
625 return None;
626 }
627 let mut tx_id = [0u8; 12];
628 tx_id.copy_from_slice(&pkt[8..20]);
629 let mut peer: Option<(IpAddr, u16)> = None;
630 let mut data: Option<Vec<u8>> = None;
631 for (t, v) in iter_attrs(pkt) {
632 match t {
633 attr::XOR_PEER_ADDRESS => {
634 peer = parse_xor_addr(v, &tx_id);
635 }
636 attr::DATA => {
637 data = Some(v.to_vec());
638 }
639 _ => {}
640 }
641 }
642 match (peer, data) {
643 (Some((ip, port)), Some(d)) => Some((ip, port, d)),
644 _ => None,
645 }
646}
647
648pub fn recv_indication(
653 allocation: &TurnAllocation,
654 timeout: Duration,
655) -> Option<(IpAddr, u16, Vec<u8>)> {
656 let socket = udp_sockets::get(allocation.socket_id)?;
657 socket.set_read_timeout(Some(timeout)).ok()?;
658 let mut buf = [0u8; 2048];
659 let (n, _src) = socket.recv_from(&mut buf).ok()?;
660 parse_data_indication(&buf[..n])
661}
662
663pub fn build_refresh(tx_id: &[u8; 12], lifetime: u32, allocation: &TurnAllocation) -> Vec<u8> {
666 let mut attrs = Vec::new();
667 push_attr(&mut attrs, attr::LIFETIME, &lifetime.to_be_bytes());
668 push_attr(&mut attrs, attr::USERNAME, allocation.username.as_bytes());
669 push_attr(&mut attrs, attr::REALM, allocation.realm.as_bytes());
670 push_attr(&mut attrs, attr::NONCE, &allocation.nonce);
671 let mut msg = build_message(msg_type::REFRESH_REQUEST, tx_id, &attrs);
672 let key = long_term_key(
673 &allocation.username,
674 &allocation.realm,
675 &allocation.password,
676 );
677 append_message_integrity(&mut msg, &key);
678 msg
679}
680
681pub fn refresh(allocation: &TurnAllocation, lifetime: u32, timeout: Duration) -> Option<u32> {
684 let socket = udp_sockets::get(allocation.socket_id)?;
685 let tx_id = fresh_tx_id();
686 let req = build_refresh(&tx_id, lifetime, allocation);
687 socket.send_to(&req, allocation.server).ok()?;
688 socket.set_read_timeout(Some(timeout)).ok()?;
689 let mut buf = [0u8; 2048];
690 loop {
691 let (n, src) = socket.recv_from(&mut buf).ok()?;
692 if src != allocation.server {
693 continue;
694 }
695 if n < 20 || buf[8..20] != tx_id {
696 continue;
697 }
698 if message_type(&buf[..n]) != msg_type::REFRESH_SUCCESS {
699 return None;
700 }
701 for (t, v) in iter_attrs(&buf[..n]) {
702 if t == attr::LIFETIME && v.len() >= 4 {
703 return Some(u32::from_be_bytes([v[0], v[1], v[2], v[3]]));
704 }
705 }
706 return Some(lifetime); }
708}
709
710#[cfg(test)]
711mod tests {
712 use super::*;
713
714 #[test]
715 fn long_term_key_matches_rfc8489_format() {
716 let k = long_term_key("user", "example.org", "pass");
720 let hex: String = k.iter().map(|b| format!("{:02x}", b)).collect();
721 assert_eq!(hex, "abca35356f4b00fbc33e2d8c2c43b9d6");
722 }
723
724 #[test]
725 fn allocate_unauth_request_shape() {
726 let tx = [0u8; 12];
727 let req = build_allocate_request_unauth(&tx);
728 assert_eq!(req.len(), 28);
730 assert_eq!(message_type(&req), msg_type::ALLOCATE_REQUEST);
731 assert_eq!(u16::from_be_bytes([req[2], req[3]]), 8); }
733
734 #[test]
735 fn parse_allocate_401_round_trip() {
736 let mut attrs: Vec<u8> = Vec::new();
738 push_attr(&mut attrs, attr::ERROR_CODE, &[0, 0, 4, 1]);
740 push_attr(&mut attrs, attr::REALM, b"example.org");
741 push_attr(&mut attrs, attr::NONCE, b"nonce-abcdef");
742 let pkt = build_message(msg_type::ALLOCATE_ERROR, &[0u8; 12], &attrs);
743 let (realm, nonce) = parse_allocate_401(&pkt).expect("401 must parse");
744 assert_eq!(realm, "example.org");
745 assert_eq!(nonce, b"nonce-abcdef");
746 }
747
748 #[test]
749 fn parse_allocate_success_round_trip() {
750 let tx = [0xAAu8; 12];
753 let mut attrs: Vec<u8> = Vec::new();
754 push_xor_addr_attr(
755 &mut attrs,
756 attr::XOR_RELAYED_ADDRESS,
757 IpAddr::V4(Ipv4Addr::new(198, 51, 100, 7)),
758 50001,
759 &tx,
760 );
761 push_attr(&mut attrs, attr::LIFETIME, &600u32.to_be_bytes());
762 let pkt = build_message(msg_type::ALLOCATE_SUCCESS, &tx, &attrs);
763 let (ip, port, lifetime) = parse_allocate_success(&pkt).expect("success must parse");
764 assert_eq!(ip, IpAddr::V4(Ipv4Addr::new(198, 51, 100, 7)));
765 assert_eq!(port, 50001);
766 assert_eq!(lifetime, 600);
767 }
768
769 #[test]
770 fn send_indication_and_data_indication_round_trip() {
771 let tx = [0xBBu8; 12];
776 let mut send = build_send_indication(
777 &tx,
778 IpAddr::V4(Ipv4Addr::new(192, 0, 2, 99)),
779 42424,
780 b"hello peer",
781 );
782 send[0..2].copy_from_slice(&msg_type::DATA_INDICATION.to_be_bytes());
784 let (peer_ip, peer_port, payload) = parse_data_indication(&send).expect("DATA must parse");
785 assert_eq!(peer_ip, IpAddr::V4(Ipv4Addr::new(192, 0, 2, 99)));
786 assert_eq!(peer_port, 42424);
787 assert_eq!(payload, b"hello peer");
788 }
789
790 #[test]
791 fn message_integrity_appended_with_correct_length() {
792 let tx = [0u8; 12];
795 let mut attrs: Vec<u8> = Vec::new();
796 push_attr(&mut attrs, attr::USERNAME, b"alice");
797 let attrs_len_before = attrs.len();
798 let mut msg = build_message(msg_type::ALLOCATE_REQUEST, &tx, &attrs);
799 let key = long_term_key("alice", "example.org", "secret");
800 append_message_integrity(&mut msg, &key);
801 let final_len = u16::from_be_bytes([msg[2], msg[3]]) as usize;
802 assert_eq!(final_len, attrs_len_before + 24);
803 assert_eq!(msg.len(), 20 + attrs_len_before + 24);
805 let mi_start = msg.len() - 24;
807 assert_eq!(
808 u16::from_be_bytes([msg[mi_start], msg[mi_start + 1]]),
809 attr::MESSAGE_INTEGRITY
810 );
811 assert_eq!(
812 u16::from_be_bytes([msg[mi_start + 2], msg[mi_start + 3]]),
813 20
814 );
815 }
816
817 #[test]
824 fn hmac_sha1_helper_matches_rfc_2202_test_vector() {
825 let key = [0x0bu8; 20];
826 let data = b"Hi There";
827 let mac = hmac_sha1(&key, data);
828 let hex: String = mac.iter().map(|b| format!("{:02x}", b)).collect();
829 assert_eq!(hex, "b617318655057264e28bc0b6fb378c8ef146be00");
830 }
831
832 #[test]
841 fn end_to_end_against_mock_turn_server() {
842 use std::net::UdpSocket;
843 use std::thread;
844
845 const USER: &str = "alice";
846 const PASS: &str = "wonderland";
847 const REALM: &str = "turn.example";
848 const NONCE: &[u8] = b"nonce-xyz-123";
849
850 let turn = UdpSocket::bind("127.0.0.1:0").expect("bind mock turn");
852 let turn_addr = turn.local_addr().unwrap();
853
854 thread::spawn(move || {
858 let mut buf = [0u8; 2048];
859 let (n1, src) = turn.recv_from(&mut buf).expect("recv 1");
861 assert_eq!(message_type(&buf[..n1]), msg_type::ALLOCATE_REQUEST);
862 let tx1: [u8; 12] = buf[8..20].try_into().unwrap();
863 let mut attrs1: Vec<u8> = Vec::new();
864 push_attr(&mut attrs1, attr::ERROR_CODE, &[0, 0, 4, 1]); push_attr(&mut attrs1, attr::REALM, REALM.as_bytes());
866 push_attr(&mut attrs1, attr::NONCE, NONCE);
867 let resp1 = build_message(msg_type::ALLOCATE_ERROR, &tx1, &attrs1);
868 turn.send_to(&resp1, src).expect("send 401");
869
870 let (n2, _src2) = turn.recv_from(&mut buf).expect("recv 2");
872 assert_eq!(message_type(&buf[..n2]), msg_type::ALLOCATE_REQUEST);
873 let tx2: [u8; 12] = buf[8..20].try_into().unwrap();
878 let mut attrs2: Vec<u8> = Vec::new();
879 push_xor_addr_attr(
880 &mut attrs2,
881 attr::XOR_RELAYED_ADDRESS,
882 IpAddr::V4(Ipv4Addr::new(198, 51, 100, 99)),
883 49999,
884 &tx2,
885 );
886 push_attr(&mut attrs2, attr::LIFETIME, &600u32.to_be_bytes());
887 let resp2 = build_message(msg_type::ALLOCATE_SUCCESS, &tx2, &attrs2);
888 turn.send_to(&resp2, src).expect("send success");
889
890 let (n3, _src3) = turn.recv_from(&mut buf).expect("recv 3");
892 assert_eq!(
893 message_type(&buf[..n3]),
894 msg_type::CREATE_PERMISSION_REQUEST
895 );
896 let tx3: [u8; 12] = buf[8..20].try_into().unwrap();
897 let resp3 = build_message(msg_type::CREATE_PERMISSION_SUCCESS, &tx3, &[]);
898 turn.send_to(&resp3, src).expect("send perm success");
899
900 let (n4, _src4) = turn.recv_from(&mut buf).expect("recv 4");
902 assert_eq!(message_type(&buf[..n4]), msg_type::SEND_INDICATION);
903 let tx4: [u8; 12] = buf[8..20].try_into().unwrap();
905 let mut peer: Option<(IpAddr, u16)> = None;
906 let mut data: Option<Vec<u8>> = None;
907 for (t, v) in iter_attrs(&buf[..n4]) {
908 if t == attr::XOR_PEER_ADDRESS {
909 peer = parse_xor_addr(v, &tx4);
910 } else if t == attr::DATA {
911 data = Some(v.to_vec());
912 }
913 }
914 let (peer_ip, peer_port) = peer.expect("XOR-PEER in send");
915 let payload = data.expect("DATA in send");
916 let mut attrs4: Vec<u8> = Vec::new();
918 push_xor_addr_attr(
919 &mut attrs4,
920 attr::XOR_PEER_ADDRESS,
921 peer_ip,
922 peer_port,
923 &tx4,
924 );
925 push_attr(&mut attrs4, attr::DATA, &payload);
926 let resp4 = build_message(msg_type::DATA_INDICATION, &tx4, &attrs4);
927 turn.send_to(&resp4, src).expect("send data ind");
928 });
929
930 let socket_id = udp_sockets::open("127.0.0.1", 0).expect("client bind");
932 let alloc = allocate(
933 socket_id,
934 &turn_addr.ip().to_string(),
935 turn_addr.port(),
936 USER,
937 PASS,
938 Duration::from_secs(2),
939 )
940 .expect("allocate must succeed against mock");
941 assert_eq!(alloc.realm, REALM);
942 assert_eq!(alloc.nonce, NONCE);
943 assert_eq!(alloc.relay_ip, IpAddr::V4(Ipv4Addr::new(198, 51, 100, 99)));
944 assert_eq!(alloc.relay_port, 49999);
945 assert_eq!(alloc.lifetime_secs, 600);
946
947 let peer_ip = IpAddr::V4(Ipv4Addr::new(192, 0, 2, 50));
948 assert!(
949 create_permission(&alloc, peer_ip, Duration::from_secs(2)),
950 "create_permission must succeed"
951 );
952
953 let sent = send_to_peer(&alloc, peer_ip, 12345, b"hello via turn")
954 .expect("send_to_peer must report bytes sent");
955 assert!(sent > 0);
956
957 let (pip, pport, payload) =
958 recv_indication(&alloc, Duration::from_secs(2)).expect("data ind");
959 assert_eq!(pip, peer_ip);
960 assert_eq!(pport, 12345);
961 assert_eq!(payload, b"hello via turn");
962
963 udp_sockets::close(socket_id);
964 }
965}