1use crate::protobuf::{self as p, Field, Value};
6use anyhow::{bail, ensure, Result};
7use std::net::{Ipv4Addr, SocketAddrV4};
8use zeroize::Zeroizing;
9
10const MAX_PACKET: usize = 8197;
11const MAX_BODY: usize = 8192;
12
13pub struct SelectedRelay {
16 pub room_id: u64,
17 pub room_key: u64,
18 pub own_member: u16,
19 pub connection_id: u16,
20 pub endpoint: SocketAddrV4,
21 pub media_key: Zeroizing<[u8; 32]>,
22 pub merge_mode: bool,
23}
24impl SelectedRelay {
25 pub fn from_strategy(
28 room_id: u64,
29 room_key: u64,
30 own_member: u16,
31 strategy: &[u8],
32 connection_index: usize,
33 udp_index: usize,
34 ) -> Result<Self> {
35 ensure!(room_id != 0 && room_key != 0, "Unallocated relay room");
36 let strategy = fields(strategy)?;
37 let connections = repeated(&strategy, 15, 32)?;
38 let connection = fields(
39 connections
40 .get(connection_index)
41 .ok_or_else(|| anyhow::anyhow!("Relay connection selection unavailable"))?,
42 )?;
43 let connection_id = u16::try_from(number(&connection, 1, None)?)?;
44 if let Some(nic) = p::optional_data(&connection, 2)? {
45 ensure!(
46 nic.len() <= 128 && !nic.contains(&0),
47 "Invalid relay NIC identity"
48 );
49 std::str::from_utf8(nic)?;
50 }
51 u16::try_from(number(&connection, 3, Some(0))?)?;
52 let endpoints = repeated(&connection, 4, 32)?;
53 let endpoint = fields(
54 endpoints
55 .get(udp_index)
56 .ok_or_else(|| anyhow::anyhow!("Relay UDP selection unavailable"))?,
57 )?;
58 let address = ipv4(data(&endpoint, 1)?, false)?;
59 let port = u16::try_from(number(&endpoint, 2, None)?)?;
60 ensure!(port != 0, "Invalid relay endpoint port");
61 let key = data(&strategy, 10)?;
62 ensure!(key.len() == 32, "Unsupported relay media key size");
63 Ok(Self {
64 room_id,
65 room_key,
66 own_member,
67 connection_id,
68 endpoint: SocketAddrV4::new(address, port),
69 media_key: Zeroizing::new(key.try_into()?),
70 merge_mode: number(&strategy, 16, Some(0))? & 1 != 0,
71 })
72 }
73}
74
75#[derive(Clone, Copy, Debug, PartialEq, Eq)]
76pub struct RelayEpoch {
77 pub account_generation: u64,
78 pub logout_epoch: u64,
79 pub call_generation: u64,
80 pub key_generation: u64,
81 pub socket_generation: u64,
82 pub attempt_id: u64,
83}
84impl RelayEpoch {
85 fn validate(self) -> Result<()> {
86 ensure!(
87 [
88 self.account_generation,
89 self.call_generation,
90 self.key_generation,
91 self.socket_generation,
92 self.attempt_id
93 ]
94 .into_iter()
95 .all(|v| v != 0),
96 "Inactive relay generation"
97 );
98 Ok(())
99 }
100}
101
102#[derive(Clone)]
105pub struct RoomInputs {
106 pub room_id: u64,
107 pub own_member: u16,
108 pub connection_id: u16,
109 pub client_ip: u32,
110 pub client_text: String,
111 pub client_port: u16,
112 pub server_ip: u32,
113 pub server_text: String,
114 pub server_port: u16,
115 pub checkin_sequence: u16,
116 pub network_type: u16,
117 pub arq_flag: u16,
118 pub has_accept: bool,
119 pub data_sequence: u32,
120 pub mix_timestamp: u32,
121 pub mix_sequence: u16,
122 pub merge_mode: bool,
123 pub header_timestamp: u32,
124 pub body_timestamp: u32,
125}
126impl RoomInputs {
127 pub fn initial(
128 selected: &SelectedRelay,
129 network_type: u16,
130 header_timestamp: u32,
131 body_timestamp: u32,
132 ) -> Self {
133 Self {
134 room_id: selected.room_id,
135 own_member: selected.own_member,
136 connection_id: selected.connection_id,
137 client_ip: 0,
138 client_text: String::new(),
139 client_port: 0,
140 server_ip: u32::from_le_bytes(selected.endpoint.ip().octets()),
141 server_text: selected.endpoint.ip().to_string(),
142 server_port: selected.endpoint.port(),
143 checkin_sequence: 1,
144 network_type,
145 arq_flag: 0,
146 has_accept: true,
147 data_sequence: 0,
148 mix_timestamp: 0,
149 mix_sequence: 0,
150 merge_mode: selected.merge_mode,
151 header_timestamp,
152 body_timestamp,
153 }
154 }
155 fn validate(&self) -> Result<()> {
156 ensure!(self.room_id != 0, "Unallocated relay room");
157 for text in [&self.client_text, &self.server_text] {
158 ensure!(
159 text.len() <= 128 && text.is_ascii() && !text.as_bytes().contains(&0),
160 "Invalid relay address text"
161 );
162 }
163 Ok(())
164 }
165 pub fn body(&self) -> Result<Vec<u8>> {
166 self.validate()?;
167 let mut values = vec![
168 p::uint(1, 0),
169 p::uint(2, self.room_id & 0xffff_ffff),
170 p::uint(3, u64::from(self.client_ip)),
171 p::uint(4, u64::from(self.server_ip)),
172 p::uint(5, u64::from(self.client_port)),
173 p::uint(6, u64::from(self.server_port)),
174 p::uint(7, u64::from(self.checkin_sequence)),
175 p::uint(8, u64::from(self.own_member)),
176 p::uint(9, u64::from(self.own_member)),
177 p::uint(10, u64::from(self.body_timestamp)),
178 p::uint(12, u64::from(self.arq_flag)),
179 p::uint(13, u64::from(self.network_type)),
180 p::bytes(14, self.client_text.as_bytes()),
181 p::bytes(15, self.server_text.as_bytes()),
182 p::uint(16, 1),
183 p::uint(17, u64::from(self.data_sequence)),
184 p::uint(18, u64::from(self.mix_timestamp)),
185 p::uint(19, u64::from(self.mix_sequence)),
186 p::uint(20, u64::from(self.has_accept)),
187 ];
188 if self.merge_mode {
189 values.push(p::uint(21, 1));
190 }
191 bounded_message(&values)
192 }
193 pub fn random_bytes_needed(&self) -> Result<usize> {
194 Ok((8 - (self.body()?.len() + 10) % 8) % 8 + 3)
195 }
196 fn packet(&self, room_key: u64, random: &[u8]) -> Result<Vec<u8>> {
197 ensure!(!self.merge_mode, "Merged relay check-in unsupported");
198 let cipher = encrypt_checkin(&self.body()?, &*checkin_key(room_key)?, random)?;
199 let pub_header = bounded_message(&[p::uint(1, 2), p::uint(2, 3), p::uint(3, 0)])?;
200 let (room32, room64) = room_pair(self.room_id);
201 let header = bounded_message(&[
202 p::bytes(1, &pub_header),
203 p::uint(2, room32),
204 p::uint(3, 10),
205 p::uint(4, u64::from(self.own_member)),
206 p::bytes(5, &[]),
207 p::uint(6, u64::from(self.own_member)),
208 p::uint(8, u64::from(self.header_timestamp)),
209 p::uint(9, room64),
210 p::uint(10, u64::from(self.connection_id)),
211 ])?;
212 frame_outer(&bounded_message(&[
213 p::bytes(1, &header),
214 p::uint(2, cipher.len() as u64),
215 p::bytes(3, &cipher),
216 ])?)
217 }
218}
219
220#[derive(Clone, Copy, Debug, PartialEq, Eq)]
221pub enum RelayProgress {
222 Opaque,
223 FirstCheckin,
224 DuplicateCheckin,
225 Ready,
226}
227#[derive(Clone, Copy, Debug, PartialEq, Eq)]
228enum Phase {
229 New,
230 AwaitingCheckin,
231 ContinuationPending,
232 AwaitingReady,
233 Ready,
234 Closed,
235}
236
237pub struct TwoRttRelay {
240 room: RoomInputs,
241 key: Zeroizing<u64>,
242 endpoint: SocketAddrV4,
243 epoch: RelayEpoch,
244 deadline_ms: u64,
245 last_ms: Option<u64>,
246 phase: Phase,
247}
248impl TwoRttRelay {
249 pub fn new(
250 room: RoomInputs,
251 room_key: u64,
252 endpoint: SocketAddrV4,
253 epoch: RelayEpoch,
254 deadline_ms: u64,
255 ) -> Result<Self> {
256 room.validate()?;
257 epoch.validate()?;
258 ensure!(
259 room_key != 0 && endpoint.port() != 0,
260 "Invalid relay key or endpoint"
261 );
262 ensure!(
263 room.server_text == endpoint.ip().to_string()
264 && room.server_ip == u32::from_le_bytes(endpoint.ip().octets())
265 && room.server_port == endpoint.port(),
266 "Relay request endpoint mismatch"
267 );
268 Ok(Self {
269 room,
270 key: Zeroizing::new(room_key),
271 endpoint,
272 epoch,
273 deadline_ms,
274 last_ms: None,
275 phase: Phase::New,
276 })
277 }
278 pub fn room(&self) -> &RoomInputs {
279 &self.room
280 }
281 pub fn is_ready(&self) -> bool {
282 self.phase == Phase::Ready
283 }
284 pub fn random_bytes_needed(&self) -> Result<usize> {
285 self.room.random_bytes_needed()
286 }
287 pub fn continuation_random_bytes_needed(
288 &self,
289 header_timestamp: u32,
290 body_timestamp: u32,
291 ) -> Result<usize> {
292 let mut room = self.room.clone();
293 room.header_timestamp = header_timestamp;
294 room.body_timestamp = body_timestamp;
295 room.random_bytes_needed()
296 }
297
298 fn live(&mut self, epoch: RelayEpoch, now_ms: u64) -> Result<()> {
299 if epoch.validate().is_err()
300 || epoch != self.epoch
301 || now_ms >= self.deadline_ms
302 || self.last_ms.is_some_and(|last| now_ms < last)
303 || self.phase == Phase::Closed
304 {
305 self.close();
306 bail!("Relay generation, clock or deadline changed");
307 }
308 self.last_ms = Some(now_ms);
309 Ok(())
310 }
311 pub fn prepare_initial(
312 &mut self,
313 epoch: RelayEpoch,
314 now_ms: u64,
315 random: &[u8],
316 ) -> Result<Vec<u8>> {
317 self.live(epoch, now_ms)?;
318 ensure!(
319 self.phase == Phase::New,
320 "Relay initial check-in already spent"
321 );
322 self.phase = Phase::Closed;
323 let packet = self.room.packet(*self.key, random)?;
324 self.phase = Phase::AwaitingCheckin;
325 Ok(packet)
326 }
327 pub fn prepare_continuation(
328 &mut self,
329 epoch: RelayEpoch,
330 now_ms: u64,
331 header_timestamp: u32,
332 body_timestamp: u32,
333 random: &[u8],
334 ) -> Result<Vec<u8>> {
335 self.live(epoch, now_ms)?;
336 ensure!(
337 self.phase == Phase::ContinuationPending,
338 "Relay continuation unavailable or spent"
339 );
340 self.phase = Phase::Closed;
341 self.room.header_timestamp = header_timestamp;
342 self.room.body_timestamp = body_timestamp;
343 let packet = self.room.packet(*self.key, random)?;
344 self.phase = Phase::AwaitingReady;
345 Ok(packet)
346 }
347 pub fn receive(
348 &mut self,
349 packet: &[u8],
350 source: SocketAddrV4,
351 epoch: RelayEpoch,
352 now_ms: u64,
353 ) -> Result<RelayProgress> {
354 self.live(epoch, now_ms)?;
355 ensure!(
356 matches!(
357 self.phase,
358 Phase::AwaitingCheckin | Phase::ContinuationPending | Phase::AwaitingReady
359 ),
360 "Relay receive unavailable"
361 );
362 let result = self.receive_checked(packet, source);
363 if result.is_err() {
364 self.close();
365 }
366 result
367 }
368 fn receive_checked(&mut self, packet: &[u8], source: SocketAddrV4) -> Result<RelayProgress> {
369 ensure!(source == self.endpoint, "Unexpected relay source endpoint");
370 ensure!(packet.len() <= MAX_PACKET, "Relay packet too large");
371 if packet.first() != Some(&0xd5) {
372 return Ok(RelayProgress::Opaque);
373 }
374 let outer = fields(unframe_outer(packet)?)?;
375 let header = fields(data(&outer, 1)?)?;
376 let public = fields(data(&header, 1)?)?;
377 let command = number(&public, 1, None)?;
378 if !matches!(command, 0x1002 | 0x1004) {
379 return Ok(RelayProgress::Opaque);
380 }
381 ensure!(
382 number(&public, 2, None)? == 3 && number(&public, 3, None)? == 0,
383 "Unsupported relay response profile"
384 );
385 let (room32, room64) = room_pair(self.room.room_id);
386 ensure!(
387 number(&header, 2, None)? == room32
388 && number(&header, 5, Some(0))? == room64
389 && number(&header, 3, None)? == 10
390 && number(&header, 7, Some(0))? == 0,
391 "Relay response context mismatch"
392 );
393 let cipher = data(&outer, 3)?;
394 ensure!(
395 number(&outer, 2, None)? == cipher.len() as u64,
396 "Relay response length mismatch"
397 );
398 let clear = decrypt_checkin(cipher, &*checkin_key(*self.key)?, 4096)?;
399 if command == 0x1002 && self.phase != Phase::AwaitingCheckin {
400 return Ok(RelayProgress::DuplicateCheckin);
401 }
402 let body = fields(&clear)?;
403 if command == 0x1004 {
404 for n in [1, 2, 3, 5, 6, 7] {
405 let v = number(&body, n, None)?;
406 if n != 1 {
407 u32::try_from(v)?;
408 }
409 }
410 repeated(&body, 4, 64)?;
411 ensure!(
412 [number(&body, 5, None)?, number(&body, 7, None)?]
413 .contains(&u64::from(self.room.own_member)),
414 "Relay Ready member mismatch"
415 );
416 self.phase = Phase::Ready;
417 return Ok(RelayProgress::Ready);
418 }
419 for n in 1..=9 {
420 u32::try_from(number(&body, n, None)?)?;
421 }
422 ensure!(
423 number(&body, 6, None)? == u64::from(self.room.checkin_sequence)
424 && number(&body, 14, Some(0))? == 0,
425 "Relay check-in sequence or merge mismatch"
426 );
427 let client = p::optional_data(&body, 12)?.unwrap_or_default();
428 let server = p::optional_data(&body, 13)?.unwrap_or_default();
429 let client_address = ipv4(client, true)?;
430 let server_address = ipv4(server, true)?;
431 let client_numeric = number(&body, 2, None)? as u32;
432 self.room.client_ip = if client_numeric == 0 {
433 u32::from_le_bytes(client_address.octets())
434 } else {
435 client_numeric
436 };
437 self.room.client_text = std::str::from_utf8(client)?.to_owned();
438 self.room.server_text = std::str::from_utf8(server)?.to_owned();
439 self.room.server_ip = u32::from_le_bytes(server_address.octets());
440 self.room.client_port = number(&body, 4, None)? as u16;
441 self.room.server_port = number(&body, 5, None)? as u16;
442 self.phase = Phase::ContinuationPending;
443 Ok(RelayProgress::FirstCheckin)
444 }
445 pub fn close(&mut self) {
446 self.key = Zeroizing::new(0);
447 self.phase = Phase::Closed;
448 }
449}
450
451fn room_pair(room: u64) -> (u64, u64) {
452 if room <= u64::from(u32::MAX) {
453 (room, 0)
454 } else {
455 (0, room)
456 }
457}
458fn fields(raw: &[u8]) -> Result<Vec<Field>> {
459 ensure!(raw.len() <= MAX_BODY, "Relay message too large");
460 super::signaling::decode_fields(raw)
461}
462fn bounded_message(parts: &[Vec<u8>]) -> Result<Vec<u8>> {
463 let out = p::message(parts)?;
464 ensure!(out.len() <= MAX_BODY, "Relay message too large");
465 Ok(out)
466}
467fn data(values: &[Field], n: u32) -> Result<&[u8]> {
468 p::optional_data(values, n)?.ok_or_else(|| anyhow::anyhow!("Missing relay bytes field {n}"))
469}
470fn number(values: &[Field], n: u32, default: Option<u64>) -> Result<u64> {
471 match p::optional(values, n)? {
472 Some(Value::Varint(v)) => Ok(*v),
473 None => default.ok_or_else(|| anyhow::anyhow!("Missing relay integer {n}")),
474 _ => bail!("Invalid relay integer {n}"),
475 }
476}
477fn repeated(values: &[Field], n: u32, limit: usize) -> Result<Vec<&[u8]>> {
478 let mut out = Vec::new();
479 for f in values.iter().filter(|v| v.number == n) {
480 ensure!(out.len() < limit, "Too many relay entries");
481 if let Value::Bytes(raw) = &f.value {
482 ensure!(raw.len() <= 4096, "Relay entry too large");
483 fields(raw)?;
484 out.push(raw.as_slice());
485 } else {
486 bail!("Invalid relay entry wire type");
487 }
488 }
489 Ok(out)
490}
491fn ipv4(raw: &[u8], allow_empty: bool) -> Result<Ipv4Addr> {
492 if raw.is_empty() && allow_empty {
493 return Ok(Ipv4Addr::UNSPECIFIED);
494 }
495 ensure!(raw.len() <= 15, "Relay IPv4 text too large");
496 let text = std::str::from_utf8(raw)?;
497 let ip: Ipv4Addr = text.parse()?;
498 ensure!(ip.to_string() == text, "Noncanonical relay IPv4 address");
499 Ok(ip)
500}
501fn checkin_key(room_key: u64) -> Result<Zeroizing<[u8; 16]>> {
502 ensure!(room_key != 0, "Missing relay key");
503 let digest = openssl::hash::hash(openssl::hash::MessageDigest::md5(), &room_key.to_le_bytes())?;
504 Ok(Zeroizing::new(digest.as_ref().try_into()?))
505}
506
507pub fn frame_outer(body: &[u8]) -> Result<Vec<u8>> {
508 ensure!(
509 !body.is_empty() && body.len() <= MAX_BODY,
510 "Invalid relay outer size"
511 );
512 let mut out = vec![0xd5];
513 out.extend(crc32(body).to_be_bytes());
514 out.extend(body);
515 Ok(out)
516}
517pub fn unframe_outer(packet: &[u8]) -> Result<&[u8]> {
518 ensure!(
519 (6..=MAX_PACKET).contains(&packet.len()) && packet[0] == 0xd5,
520 "Invalid relay outer packet"
521 );
522 let body = &packet[5..];
523 ensure!(
524 u32::from_be_bytes(packet[1..5].try_into()?) == crc32(body),
525 "Relay CRC mismatch"
526 );
527 Ok(body)
528}
529fn crc32(body: &[u8]) -> u32 {
530 let mut value = u32::MAX;
531 for byte in body {
532 value ^= u32::from(*byte);
533 for _ in 0..8 {
534 value = (value >> 1) ^ if value & 1 != 0 { 0xedb88320 } else { 0 };
535 }
536 }
537 value ^ u32::MAX
538}
539fn tea(block: [u8; 8], key: &[u8; 16], decrypt: bool) -> [u8; 8] {
540 let mut a = u32::from_be_bytes(block[..4].try_into().expect("block width"));
541 let mut b = u32::from_be_bytes(block[4..].try_into().expect("block width"));
542 let k: [u32; 4] = std::array::from_fn(|n| {
543 u32::from_be_bytes(key[n * 4..n * 4 + 4].try_into().expect("key width"))
544 });
545 if decrypt {
546 let mut sum = 0xe3779b90u32;
547 for _ in 0..16 {
548 b = b.wrapping_sub(
549 (a.wrapping_shl(4).wrapping_add(k[2]))
550 ^ (a.wrapping_add(sum))
551 ^ ((a >> 5).wrapping_add(k[3])),
552 );
553 a = a.wrapping_sub(
554 (b.wrapping_shl(4).wrapping_add(k[0]))
555 ^ (b.wrapping_add(sum))
556 ^ ((b >> 5).wrapping_add(k[1])),
557 );
558 sum = sum.wrapping_sub(0x9e3779b9);
559 }
560 } else {
561 let mut sum = 0u32;
562 for _ in 0..16 {
563 sum = sum.wrapping_add(0x9e3779b9);
564 a = a.wrapping_add(
565 (b.wrapping_shl(4).wrapping_add(k[0]))
566 ^ (b.wrapping_add(sum))
567 ^ ((b >> 5).wrapping_add(k[1])),
568 );
569 b = b.wrapping_add(
570 (a.wrapping_shl(4).wrapping_add(k[2]))
571 ^ (a.wrapping_add(sum))
572 ^ ((a >> 5).wrapping_add(k[3])),
573 );
574 }
575 }
576 let mut out = [0; 8];
577 out[..4].copy_from_slice(&a.to_be_bytes());
578 out[4..].copy_from_slice(&b.to_be_bytes());
579 out
580}
581pub fn encrypt_checkin(plain: &[u8], key: &[u8; 16], random: &[u8]) -> Result<Vec<u8>> {
583 ensure!(plain.len() <= 4096, "Relay check-in plaintext too large");
584 let pad = (8 - (plain.len() + 10) % 8) % 8;
585 ensure!(
586 random.len() == pad + 3,
587 "Wrong relay check-in randomness length"
588 );
589 let mut clear = Zeroizing::new(Vec::with_capacity(plain.len() + pad + 10));
590 clear.push((random[0] & 0xf8) | pad as u8);
591 clear.extend(&random[1..]);
592 clear.extend(plain);
593 clear.extend([0; 7]);
594 let mut previous_cipher = [0; 8];
595 let mut previous_x = [0; 8];
596 let mut out = Vec::with_capacity(clear.len());
597 for block in clear.chunks_exact(8) {
598 let x = std::array::from_fn(|n| block[n] ^ previous_cipher[n]);
599 let encrypted = tea(x, key, false);
600 let cipher = std::array::from_fn(|n| encrypted[n] ^ previous_x[n]);
601 out.extend(cipher);
602 previous_x = x;
603 previous_cipher = cipher;
604 }
605 Ok(out)
606}
607pub fn decrypt_checkin(cipher: &[u8], key: &[u8; 16], limit: usize) -> Result<Zeroizing<Vec<u8>>> {
608 ensure!(
609 (16..=4113).contains(&cipher.len()) && cipher.len().is_multiple_of(8) && limit <= 4096,
610 "Invalid relay check-in ciphertext size"
611 );
612 let mut previous_cipher = [0; 8];
613 let mut previous_x = [0; 8];
614 let mut clear = Zeroizing::new(Vec::with_capacity(cipher.len()));
615 for block in cipher.chunks_exact(8) {
616 let c: [u8; 8] = block.try_into()?;
617 let x = tea(std::array::from_fn(|n| c[n] ^ previous_x[n]), key, true);
618 clear.extend((0..8).map(|n| x[n] ^ previous_cipher[n]));
619 previous_x = x;
620 previous_cipher = c;
621 }
622 let start = usize::from(clear[0] & 7) + 3;
623 ensure!(
624 start + 7 <= clear.len() && clear[clear.len() - 7..] == [0; 7],
625 "Invalid relay check-in trailer"
626 );
627 ensure!(
628 clear.len() - start - 7 <= limit,
629 "Relay check-in output exceeds limit"
630 );
631 Ok(Zeroizing::new(clear[start..clear.len() - 7].to_vec()))
632}
633
634#[cfg(test)]
635mod tests {
636 use super::*;
637 #[test]
638 fn tea_and_crc_literal_vectors() {
639 assert_eq!(
640 tea([0; 8], &[0; 16], false),
641 [0xa8, 0x89, 0xf7, 0x98, 0x18, 0x2d, 0x80, 0x83]
642 );
643 assert_eq!(
644 tea(
645 [0xa8, 0x89, 0xf7, 0x98, 0x18, 0x2d, 0x80, 0x83],
646 &[0; 16],
647 true
648 ),
649 [0; 8]
650 );
651 assert_eq!(crc32(b"123456789"), 0xcbf43926);
652 }
653 #[test]
654 fn transform_roundtrip_structural_and_output_bounds() {
655 for n in [0, 1, 7, 8, 128, 4096] {
656 let input = vec![42; n];
657 let random = vec![9; (8 - (n + 10) % 8) % 8 + 3];
658 let key = [7; 16];
659 let cipher = encrypt_checkin(&input, &key, &random).unwrap();
660 assert_eq!(&*decrypt_checkin(&cipher, &key, 4096).unwrap(), &input);
661 assert!(decrypt_checkin(&cipher, &key, n.saturating_sub(1)).is_err() || n == 0);
662 let mut corrupt = cipher;
663 *corrupt.last_mut().unwrap() ^= 1;
664 assert!(decrypt_checkin(&corrupt, &key, 4096).is_err());
665 }
666 }
667 fn epoch() -> RelayEpoch {
668 RelayEpoch {
669 account_generation: 1,
670 logout_epoch: 0,
671 call_generation: 1,
672 key_generation: 1,
673 socket_generation: 1,
674 attempt_id: 1,
675 }
676 }
677 fn selected() -> SelectedRelay {
678 SelectedRelay {
679 room_id: 7,
680 room_key: 9,
681 own_member: 0,
682 connection_id: 1,
683 endpoint: SocketAddrV4::new(Ipv4Addr::LOCALHOST, 6000),
684 media_key: Zeroizing::new([3; 32]),
685 merge_mode: false,
686 }
687 }
688 fn reply(command: u64, body: &[u8]) -> Vec<u8> {
689 let public = p::message(&[p::uint(1, command), p::uint(2, 3), p::uint(3, 0)]).unwrap();
690 let header = p::message(&[p::bytes(1, &public), p::uint(2, 7), p::uint(3, 10)]).unwrap();
691 let rand = vec![5; (8 - (body.len() + 10) % 8) % 8 + 3];
692 let encrypted = encrypt_checkin(body, &checkin_key(9).unwrap(), &rand).unwrap();
693 frame_outer(
694 &p::message(&[
695 p::bytes(1, &header),
696 p::uint(2, encrypted.len() as u64),
697 p::bytes(3, &encrypted),
698 ])
699 .unwrap(),
700 )
701 .unwrap()
702 }
703 #[test]
704 fn two_turn_setup_never_changes_actual_reply_destination() {
705 let selected = selected();
706 let mut attempt = TwoRttRelay::new(
707 RoomInputs::initial(&selected, 0, 0, 0),
708 9,
709 selected.endpoint,
710 epoch(),
711 100,
712 )
713 .unwrap();
714 let random = vec![1; attempt.random_bytes_needed().unwrap()];
715 attempt.prepare_initial(epoch(), 1, &random).unwrap();
716 assert!(attempt.prepare_initial(epoch(), 2, &random).is_err());
717 let body = p::message(
718 &(1..=9)
719 .map(|n| p::uint(n, if n == 6 { 1 } else { 0 }))
720 .chain([p::bytes(12, b"192.0.2.1"), p::bytes(13, b"198.51.100.1")])
721 .collect::<Vec<_>>(),
722 )
723 .unwrap();
724 assert_eq!(
725 attempt
726 .receive(&reply(0x1002, &body), selected.endpoint, epoch(), 3)
727 .unwrap(),
728 RelayProgress::FirstCheckin
729 );
730 assert_eq!(attempt.room().server_text, "198.51.100.1");
731 let random = vec![2; attempt.random_bytes_needed().unwrap()];
732 attempt
733 .prepare_continuation(epoch(), 4, 1, 1, &random)
734 .unwrap();
735 let ready = p::message(
736 &(1..=7)
737 .filter(|n| *n != 4)
738 .map(|n| p::uint(n, 0))
739 .collect::<Vec<_>>(),
740 )
741 .unwrap();
742 assert_eq!(
743 attempt
744 .receive(&reply(0x1004, &ready), selected.endpoint, epoch(), 5)
745 .unwrap(),
746 RelayProgress::Ready
747 );
748 assert!(attempt.is_ready());
749 }
750}