1use std::fmt::{self, Formatter};
108use std::net::Ipv4Addr;
109
110use zerocopy::byteorder::{BigEndian, U16, U32};
111use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
112
113use crate::packet::protocol::IpProto;
114use crate::packet::{HeaderParser, PacketHeader, PacketHeaderError};
115
116pub const TEREDO_PORT: u16 = 3544;
118
119pub const TEREDO_TYPE_ORIGIN: u16 = 0x0000;
121
122pub const TEREDO_TYPE_AUTH: u16 = 0x0001;
124
125const IPV6_VERSION_NIBBLE: u8 = 0x60;
127const IPV6_VERSION_MASK: u8 = 0xF0;
128
129#[repr(C, packed)]
146#[derive(FromBytes, IntoBytes, Unaligned, Debug, Clone, Copy, KnownLayout, Immutable)]
147pub struct TeredoHeader {
148 indicator_type: U16<BigEndian>,
149 obfuscated_port: U16<BigEndian>,
150 obfuscated_ipv4: U32<BigEndian>,
151}
152
153impl TeredoHeader {
154 #[inline]
156 pub fn indicator_type(&self) -> u16 {
157 self.indicator_type.get()
158 }
159
160 #[inline]
162 pub fn obfuscated_port(&self) -> u16 {
163 self.obfuscated_port.get()
164 }
165
166 #[inline]
170 pub fn port(&self) -> u16 {
171 self.obfuscated_port.get() ^ 0xFFFF
172 }
173
174 #[inline]
176 pub fn obfuscated_ipv4(&self) -> u32 {
177 self.obfuscated_ipv4.get()
178 }
179
180 #[inline]
184 pub fn ipv4_addr(&self) -> Ipv4Addr {
185 Ipv4Addr::from(self.obfuscated_ipv4.get() ^ 0xFFFFFFFF)
186 }
187
188 #[inline]
190 fn is_valid(&self) -> bool {
191 self.indicator_type() == TEREDO_TYPE_ORIGIN
192 }
193}
194
195impl PacketHeader for TeredoHeader {
196 const NAME: &'static str = "TeredoHeader";
197 type InnerType = IpProto;
198
199 #[inline]
200 fn inner_type(&self) -> Self::InnerType {
201 IpProto::IPV6
203 }
204
205 #[inline]
206 fn total_len(&self, _buf: &[u8]) -> usize {
207 Self::FIXED_LEN
208 }
209
210 #[inline]
211 fn is_valid(&self) -> bool {
212 self.is_valid()
213 }
214}
215
216impl HeaderParser for TeredoHeader {
217 type Output<'a> = &'a TeredoHeader;
218
219 #[inline]
220 fn into_view<'a>(header: &'a Self, _raw_options: &'a [u8]) -> Self::Output<'a> {
221 header
222 }
223}
224
225impl fmt::Display for TeredoHeader {
226 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
227 write!(
228 f,
229 "Teredo origin port={} ipv4={}",
230 self.port(),
231 self.ipv4_addr()
232 )
233 }
234}
235
236#[repr(C, packed)]
249#[derive(FromBytes, IntoBytes, Unaligned, Debug, Clone, Copy, KnownLayout, Immutable)]
250pub struct TeredoAuthHeader {
251 indicator_type: U16<BigEndian>,
252 id_len: u8,
253 auth_len: u8,
254}
255
256impl TeredoAuthHeader {
257 pub const FIXED_SIZE: usize = 4;
259
260 pub const NONCE_SIZE: usize = 8;
262
263 pub const CONFIRMATION_SIZE: usize = 1;
265
266 #[inline]
268 pub fn indicator_type(&self) -> u16 {
269 self.indicator_type.get()
270 }
271
272 #[inline]
274 pub fn id_len(&self) -> u8 {
275 self.id_len
276 }
277
278 #[inline]
280 pub fn auth_len(&self) -> u8 {
281 self.auth_len
282 }
283
284 #[inline]
286 pub fn total_len(&self) -> usize {
287 Self::FIXED_SIZE
288 + self.id_len as usize
289 + self.auth_len as usize
290 + Self::NONCE_SIZE
291 + Self::CONFIRMATION_SIZE
292 }
293
294 #[inline]
296 fn is_valid(&self) -> bool {
297 self.indicator_type() == TEREDO_TYPE_AUTH
298 }
299}
300
301impl PacketHeader for TeredoAuthHeader {
302 const NAME: &'static str = "TeredoAuthHeader";
303 type InnerType = IpProto;
304
305 #[inline]
306 fn inner_type(&self) -> Self::InnerType {
307 IpProto::IPV6
308 }
309
310 #[inline]
311 fn total_len(&self, _buf: &[u8]) -> usize {
312 self.total_len()
313 }
314
315 #[inline]
316 fn is_valid(&self) -> bool {
317 self.is_valid()
318 }
319}
320
321#[derive(Debug, Clone)]
323pub struct TeredoAuthHeaderFull<'a> {
324 pub header: &'a TeredoAuthHeader,
326 pub client_id: &'a [u8],
328 pub auth_value: &'a [u8],
330 pub nonce: &'a [u8],
332 pub confirmation: u8,
334}
335
336impl<'a> TeredoAuthHeaderFull<'a> {
337 #[inline]
339 pub fn total_len(&self) -> usize {
340 self.header.total_len()
341 }
342}
343
344impl std::ops::Deref for TeredoAuthHeaderFull<'_> {
345 type Target = TeredoAuthHeader;
346
347 #[inline]
348 fn deref(&self) -> &Self::Target {
349 self.header
350 }
351}
352
353impl HeaderParser for TeredoAuthHeader {
354 type Output<'a> = TeredoAuthHeaderFull<'a>;
355
356 fn into_view<'a>(header: &'a Self, options: &'a [u8]) -> Self::Output<'a> {
357 let id_len = header.id_len() as usize;
358 let auth_len = header.auth_len() as usize;
359
360 let client_id = &options[..id_len];
361 let auth_value = &options[id_len..id_len + auth_len];
362 let nonce_start = id_len + auth_len;
363 let nonce = &options[nonce_start..nonce_start + TeredoAuthHeader::NONCE_SIZE];
364 let confirmation = options[nonce_start + TeredoAuthHeader::NONCE_SIZE];
365
366 TeredoAuthHeaderFull {
367 header,
368 client_id,
369 auth_value,
370 nonce,
371 confirmation,
372 }
373 }
374}
375
376impl fmt::Display for TeredoAuthHeaderFull<'_> {
377 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
378 write!(
379 f,
380 "TeredoAuth id_len={} auth_len={} confirmation={}",
381 self.header.id_len(),
382 self.header.auth_len(),
383 self.confirmation
384 )
385 }
386}
387
388#[derive(Debug, Clone, Copy, PartialEq, Eq)]
390pub enum TeredoIndicator {
391 Origin,
393 Authentication,
395 None,
397}
398
399impl TeredoIndicator {
400 pub fn detect(buf: &[u8]) -> Option<Self> {
402 if buf.len() < 2 {
403 return None;
404 }
405
406 if (buf[0] & IPV6_VERSION_MASK) == IPV6_VERSION_NIBBLE {
408 return Some(TeredoIndicator::None);
409 }
410
411 let indicator_type = u16::from_be_bytes([buf[0], buf[1]]);
412
413 match indicator_type {
414 TEREDO_TYPE_ORIGIN => Some(TeredoIndicator::Origin),
415 TEREDO_TYPE_AUTH => Some(TeredoIndicator::Authentication),
416 _ => None, }
418 }
419}
420
421#[derive(Debug, Clone)]
426pub struct TeredoPacket<'a> {
427 authentication: Option<TeredoAuthHeaderFull<'a>>,
429 origin_indication: Option<&'a TeredoHeader>,
431 ipv6_payload: &'a [u8],
433 header_len: usize,
435}
436
437impl<'a> TeredoPacket<'a> {
438 pub fn parse(buf: &'a [u8]) -> Result<Self, PacketHeaderError> {
444 let mut offset = 0;
445 let mut authentication = None;
446 let mut origin_indication = None;
447
448 if let Some(TeredoIndicator::Authentication) = TeredoIndicator::detect(&buf[offset..]) {
450 let (auth, rest) = TeredoAuthHeader::from_bytes(&buf[offset..])?;
451 offset = buf.len() - rest.len();
452 authentication = Some(auth);
453 }
454
455 if let Some(TeredoIndicator::Origin) = TeredoIndicator::detect(&buf[offset..]) {
457 let (origin, _) = TeredoHeader::from_bytes(&buf[offset..])?;
458 origin_indication = Some(origin);
459 offset += TeredoHeader::FIXED_LEN;
460 }
461
462 if buf.len() <= offset {
464 return Err(PacketHeaderError::TooShort("TeredoPacket"));
465 }
466
467 if (buf[offset] & IPV6_VERSION_MASK) != IPV6_VERSION_NIBBLE {
469 return Err(PacketHeaderError::Invalid("TeredoPacket: not IPv6"));
470 }
471
472 let ipv6_payload = &buf[offset..];
473
474 Ok(TeredoPacket {
475 authentication,
476 origin_indication,
477 ipv6_payload,
478 header_len: offset,
479 })
480 }
481
482 #[inline]
484 pub fn authentication(&self) -> Option<&TeredoAuthHeaderFull<'a>> {
485 self.authentication.as_ref()
486 }
487
488 #[inline]
490 pub fn origin_indication(&self) -> Option<&TeredoHeader> {
491 self.origin_indication
492 }
493
494 #[inline]
496 pub fn ipv6_payload(&self) -> &'a [u8] {
497 self.ipv6_payload
498 }
499
500 #[inline]
502 pub fn header_len(&self) -> usize {
503 self.header_len
504 }
505
506 #[inline]
508 pub fn has_indicators(&self) -> bool {
509 self.authentication.is_some() || self.origin_indication.is_some()
510 }
511}
512
513impl fmt::Display for TeredoPacket<'_> {
514 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
515 write!(f, "Teredo")?;
516
517 if let Some(auth) = &self.authentication {
518 write!(f, " [{}]", auth)?;
519 }
520
521 if let Some(origin) = self.origin_indication {
522 write!(f, " [{}]", origin)?;
523 }
524
525 write!(f, " ipv6_len={}", self.ipv6_payload.len())
526 }
527}
528
529#[inline]
531pub fn is_teredo_port(src_port: u16, dst_port: u16) -> bool {
532 src_port == TEREDO_PORT || dst_port == TEREDO_PORT
533}
534
535#[cfg(test)]
536mod tests {
537 use super::*;
538
539 fn create_minimal_ipv6() -> Vec<u8> {
540 vec![
541 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
545 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
547 0x00, 0x01,
548 ]
549 }
550
551 #[test]
552 fn test_teredo_header_size() {
553 assert_eq!(std::mem::size_of::<TeredoHeader>(), 8);
554 assert_eq!(TeredoHeader::FIXED_LEN, 8);
555 }
556
557 #[test]
558 fn test_auth_header_size() {
559 assert_eq!(std::mem::size_of::<TeredoAuthHeader>(), 4);
560 assert_eq!(TeredoAuthHeader::FIXED_SIZE, 4);
561 }
562
563 #[test]
564 fn test_teredo_header_parsing() {
565 let header = TeredoHeader {
566 indicator_type: U16::new(TEREDO_TYPE_ORIGIN),
567 obfuscated_port: U16::new(0xFFFF ^ 0x1234), obfuscated_ipv4: U32::new(0xFFFFFFFF ^ 0xC0A80164), };
570
571 assert_eq!(header.indicator_type(), TEREDO_TYPE_ORIGIN);
572 assert_eq!(header.port(), 0x1234);
573 assert_eq!(header.ipv4_addr(), Ipv4Addr::new(192, 168, 1, 100));
574 assert!(header.is_valid());
575 }
576
577 #[test]
578 fn test_teredo_header_obfuscation() {
579 let header = TeredoHeader {
581 indicator_type: U16::new(TEREDO_TYPE_ORIGIN),
582 obfuscated_port: U16::new(0xFFFF ^ 80),
583 obfuscated_ipv4: U32::new(0xFFFFFFFF ^ 0x0A000001), };
585
586 assert_eq!(header.port(), 80);
587 assert_eq!(header.ipv4_addr(), Ipv4Addr::new(10, 0, 0, 1));
588 }
589
590 #[test]
591 fn test_teredo_header_from_bytes() {
592 let mut packet = Vec::new();
593
594 packet.extend_from_slice(&0x0000u16.to_be_bytes()); packet.extend_from_slice(&(0xFFFFu16 ^ 0x1234).to_be_bytes()); packet.extend_from_slice(&(0xFFFFFFFFu32 ^ 0xC0A80101).to_be_bytes()); packet.extend_from_slice(&create_minimal_ipv6());
601
602 let (header, ipv6_payload) = TeredoHeader::from_bytes(&packet).unwrap();
603 assert_eq!(header.port(), 0x1234);
604 assert_eq!(header.ipv4_addr(), Ipv4Addr::new(192, 168, 1, 1));
605 assert_eq!(ipv6_payload.len(), 40);
606 assert_eq!(header.inner_type(), IpProto::IPV6);
607 }
608
609 #[test]
610 fn test_teredo_header_invalid_type() {
611 let mut packet = Vec::new();
612
613 packet.extend_from_slice(&0x0001u16.to_be_bytes()); packet.extend_from_slice(&0xFFFFu16.to_be_bytes());
616 packet.extend_from_slice(&0xFFFFFFFFu32.to_be_bytes());
617
618 let result = TeredoHeader::from_bytes(&packet);
619 assert!(result.is_err());
620 }
621
622 #[test]
623 fn test_teredo_header_too_short() {
624 let packet = vec![0x00, 0x00, 0xFF, 0xFF]; let result = TeredoHeader::from_bytes(&packet);
626 assert!(result.is_err());
627 }
628
629 #[test]
630 fn test_indicator_detect_ipv6() {
631 let ipv6 = create_minimal_ipv6();
632 let indicator = TeredoIndicator::detect(&ipv6);
633 assert_eq!(indicator, Some(TeredoIndicator::None));
634 }
635
636 #[test]
637 fn test_indicator_detect_origin() {
638 let buf = vec![0x00, 0x00, 0xFF, 0xFF]; let indicator = TeredoIndicator::detect(&buf);
640 assert_eq!(indicator, Some(TeredoIndicator::Origin));
641 }
642
643 #[test]
644 fn test_indicator_detect_auth() {
645 let buf = vec![0x00, 0x01, 0x00, 0x00]; let indicator = TeredoIndicator::detect(&buf);
647 assert_eq!(indicator, Some(TeredoIndicator::Authentication));
648 }
649
650 #[test]
651 fn test_parse_direct_ipv6() {
652 let packet = create_minimal_ipv6();
653
654 let teredo = TeredoPacket::parse(&packet).unwrap();
655 assert!(teredo.authentication().is_none());
656 assert!(teredo.origin_indication().is_none());
657 assert!(!teredo.has_indicators());
658 assert_eq!(teredo.header_len(), 0);
659 assert_eq!(teredo.ipv6_payload().len(), 40);
660 }
661
662 #[test]
663 fn test_parse_with_origin_indication() {
664 let mut packet = Vec::new();
665
666 packet.extend_from_slice(&0x0000u16.to_be_bytes()); packet.extend_from_slice(&(0xFFFFu16 ^ 0x1234).to_be_bytes()); packet.extend_from_slice(&(0xFFFFFFFFu32 ^ 0xC0A80101).to_be_bytes()); packet.extend_from_slice(&create_minimal_ipv6());
673
674 let teredo = TeredoPacket::parse(&packet).unwrap();
675 assert!(teredo.authentication().is_none());
676 assert!(teredo.origin_indication().is_some());
677 assert!(teredo.has_indicators());
678 assert_eq!(teredo.header_len(), 8);
679
680 let origin = teredo.origin_indication().unwrap();
681 assert_eq!(origin.port(), 0x1234);
682 assert_eq!(origin.ipv4_addr(), Ipv4Addr::new(192, 168, 1, 1));
683 }
684
685 #[test]
686 fn test_parse_with_authentication() {
687 let mut packet = Vec::new();
688
689 packet.extend_from_slice(&0x0001u16.to_be_bytes()); packet.push(4); packet.push(8); packet.extend_from_slice(&[0x01, 0x02, 0x03, 0x04]); packet.extend_from_slice(&[0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8]); packet.extend_from_slice(&[0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8]); packet.push(0x00); packet.extend_from_slice(&create_minimal_ipv6());
700
701 let teredo = TeredoPacket::parse(&packet).unwrap();
702 assert!(teredo.authentication().is_some());
703 assert!(teredo.origin_indication().is_none());
704 assert!(teredo.has_indicators());
705
706 let auth = teredo.authentication().unwrap();
707 assert_eq!(auth.header.id_len(), 4);
708 assert_eq!(auth.header.auth_len(), 8);
709 assert_eq!(auth.client_id, &[0x01, 0x02, 0x03, 0x04]);
710 assert_eq!(auth.nonce.len(), 8);
711 assert_eq!(auth.confirmation, 0x00);
712 }
713
714 #[test]
715 fn test_parse_with_auth_and_origin() {
716 let mut packet = Vec::new();
717
718 packet.extend_from_slice(&0x0001u16.to_be_bytes()); packet.push(0); packet.push(0); packet.extend_from_slice(&[0x00; 8]); packet.push(0x00); packet.extend_from_slice(&0x0000u16.to_be_bytes()); packet.extend_from_slice(&(0xFFFFu16 ^ 3544).to_be_bytes()); packet.extend_from_slice(&(0xFFFFFFFFu32 ^ 0x08080808).to_be_bytes()); packet.extend_from_slice(&create_minimal_ipv6());
732
733 let teredo = TeredoPacket::parse(&packet).unwrap();
734 assert!(teredo.authentication().is_some());
735 assert!(teredo.origin_indication().is_some());
736 assert!(teredo.has_indicators());
737
738 let origin = teredo.origin_indication().unwrap();
739 assert_eq!(origin.port(), 3544);
740 assert_eq!(origin.ipv4_addr(), Ipv4Addr::new(8, 8, 8, 8));
741 }
742
743 #[test]
744 fn test_parse_too_short() {
745 let packet = vec![0x00]; assert!(TeredoPacket::parse(&packet).is_err());
747 }
748
749 #[test]
750 fn test_parse_no_ipv6() {
751 let packet = vec![
752 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ];
757 assert!(TeredoPacket::parse(&packet).is_err());
758 }
759
760 #[test]
761 fn test_parse_invalid_ipv6_version() {
762 let mut packet = vec![
763 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ];
767 packet.extend_from_slice(&[0x40, 0x00, 0x00, 0x00]);
769
770 assert!(TeredoPacket::parse(&packet).is_err());
771 }
772
773 #[test]
774 fn test_teredo_port_check() {
775 assert!(is_teredo_port(3544, 12345));
776 assert!(is_teredo_port(12345, 3544));
777 assert!(is_teredo_port(3544, 3544));
778 assert!(!is_teredo_port(80, 443));
779 }
780
781 #[test]
782 fn test_display_teredo_header() {
783 let header = TeredoHeader {
784 indicator_type: U16::new(TEREDO_TYPE_ORIGIN),
785 obfuscated_port: U16::new(0xFFFF ^ 1234),
786 obfuscated_ipv4: U32::new(0xFFFFFFFF ^ 0x0A000001),
787 };
788
789 let display = format!("{}", header);
790 assert!(display.contains("Teredo"));
791 assert!(display.contains("port=1234"));
792 assert!(display.contains("10.0.0.1"));
793 }
794
795 #[test]
796 fn test_display_packet() {
797 let packet = create_minimal_ipv6();
798 let teredo = TeredoPacket::parse(&packet).unwrap();
799
800 let display = format!("{}", teredo);
801 assert!(display.contains("Teredo"));
802 assert!(display.contains("ipv6_len=40"));
803 }
804
805 #[test]
806 fn test_auth_total_len() {
807 let fixed = TeredoAuthHeader {
808 indicator_type: U16::new(TEREDO_TYPE_AUTH),
809 id_len: 4,
810 auth_len: 8,
811 };
812
813 assert_eq!(fixed.total_len(), 25);
815 }
816
817 #[test]
818 fn test_auth_minimal() {
819 let fixed = TeredoAuthHeader {
820 indicator_type: U16::new(TEREDO_TYPE_AUTH),
821 id_len: 0,
822 auth_len: 0,
823 };
824
825 assert_eq!(fixed.total_len(), 13);
827 assert!(fixed.is_valid());
828 }
829
830 #[test]
831 fn test_auth_header_from_bytes() {
832 let mut packet = Vec::new();
833
834 packet.extend_from_slice(&0x0001u16.to_be_bytes()); packet.push(2); packet.push(4); packet.extend_from_slice(&[0x01, 0x02]); packet.extend_from_slice(&[0xA1, 0xA2, 0xA3, 0xA4]); packet.extend_from_slice(&[0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8]); packet.push(0x42); packet.extend_from_slice(&[0x60, 0x00]); let (auth, _payload) = TeredoAuthHeader::from_bytes(&packet).unwrap();
847 assert_eq!(auth.id_len(), 2);
848 assert_eq!(auth.auth_len(), 4);
849 assert_eq!(auth.client_id, &[0x01, 0x02]);
850 assert_eq!(auth.auth_value, &[0xA1, 0xA2, 0xA3, 0xA4]);
851 assert_eq!(auth.confirmation, 0x42);
852 assert_eq!(auth.inner_type(), IpProto::IPV6);
853 }
854
855 #[test]
856 fn test_real_world_teredo_address() {
857 let header = TeredoHeader {
861 indicator_type: U16::new(TEREDO_TYPE_ORIGIN),
862 obfuscated_port: U16::new(0xFFFF ^ 40000),
863 obfuscated_ipv4: U32::new(0xFFFFFFFF ^ 0xC000022D), };
865
866 assert_eq!(header.port(), 40000);
867 assert_eq!(header.ipv4_addr(), Ipv4Addr::new(192, 0, 2, 45));
868 }
869}