22from dataclasses import dataclass , field
33from struct import pack , unpack , unpack_from
44from typing import Any , List , Optional , Tuple , Union
5+ from ipaddress import IPv4Address , IPv6Address
56
67from . import ipv6
78
89TEREDO_PORT = 3544
910TEREDO_HEADER_LENGTH = 22
1011
12+
13+ @dataclass
14+ class TeredoEndpoint :
15+ teredo_server_ipv4 : IPv4Address
16+ flags : int
17+ udp_port : int
18+ client_pub_ipv4 : IPv4Address
19+
20+
21+ def convert_teredo_addr_to_endpoint (
22+ teredo_addr : bytes
23+ ) -> TeredoEndpoint :
24+ """
25+ 0x00-0x04 Prefix // 32 bits
26+ 0x04-0x08 Teredo server IPv4 // 32 bits
27+ 0x08-0x0A Flags // 16 bits
28+ 0x0A-0x0C UDP Port // 16 bits
29+ 0x0C-0x10 Client public IPv4 // 32 bits
30+
31+ Client IP address and UDP port are obfuscated / inverted
32+ """
33+ addr = IPv6Address (teredo_addr )
34+ teredo_tuple = addr .teredo
35+ if not teredo_tuple :
36+ raise ValueError ('Not a teredo address' )
37+
38+ prefix , server_ipv4 , flags , udp_port , client_ipv4 = \
39+ unpack ('!IIHHI' , teredo_addr )
40+
41+ # Deobfuscate/invert client address and port
42+ client_ipv4 ^= 0xFFFFFFFF
43+ udp_port ^= 0xFFFF
44+
45+ # Convert IP addresses to object
46+ server_ipv4 = IPv4Address (server_ipv4 )
47+ client_ipv4 = IPv4Address (client_ipv4 )
48+
49+ assert server_ipv4 == teredo_tuple [0 ]
50+ assert client_ipv4 == teredo_tuple [1 ]
51+
52+ return TeredoEndpoint (
53+ teredo_server_ipv4 = server_ipv4 ,
54+ flags = flags ,
55+ udp_port = udp_port ,
56+ client_pub_ipv4 = client_ipv4
57+ )
58+
1159class TeredoPacket :
1260 def __init__ (
1361 self ,
14- ipv6_base : ipv6 .IPv6Packet
62+ ipv6_base : ipv6 .IPv6Packet ,
63+ src_teredo : TeredoEndpoint ,
64+ dst_teredo : TeredoEndpoint
1565 ) -> None :
1666 self .ipv6 = ipv6_base
67+ self .src_teredo = src_teredo
68+ self .dst_teredo = dst_teredo
1769
1870 def __repr__ (self ) -> str :
1971 return (
20- f"TeredoPacket(IPv6={ self .ipv6 } )"
72+ f"TeredoPacket(IPv6={ self .ipv6 } , SRC= { self . src_teredo } , DST= { self . dst_teredo } )"
2173 )
2274
2375 @classmethod
@@ -27,5 +79,7 @@ def parse(cls, data: bytes):
2779 f"Teredo packet length is less than { TEREDO_HEADER_LENGTH } bytes"
2880 )
2981 base = ipv6 .IPv6Packet .parse (data )
30- return cls (base )
82+ src_teredo = convert_teredo_addr_to_endpoint (base .src )
83+ dst_teredo = convert_teredo_addr_to_endpoint (base .dst )
84+ return cls (base , src_teredo , dst_teredo )
3185
0 commit comments