Skip to content

Commit 867b94f

Browse files
committed
PCAP: Parse teredo-wrapped payloads
1 parent 8fa4457 commit 867b94f

3 files changed

Lines changed: 47 additions & 24 deletions

File tree

xcloud/protocol/ipv6.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import dpkt
2+
from typing import Any
3+
from enum import Enum
4+
5+
NO_NEXT_HEADER = 59
26

37
class IPv6Packet:
48
def __init__(
@@ -40,12 +44,12 @@ def dst(self) -> bytes:
4044
return self.ipv6_base.dst
4145

4246
@property
43-
def data(self) -> bytes:
47+
def data(self) -> Any:
4448
return self.ipv6_base.data
4549

4650
def __repr__(self):
4751
return (
48-
f"IPv6Packet(V={self.version}, SRC={self.src}, DST={self.dst}, PLEN={self.payload_len} NEXT={self.next_header} HLIM={self.hop_limit}) DATA={self.data}"
52+
f"IPv6Packet(V={self.version}, SRC={self.src}, DST={self.dst}, PLEN={self.payload_len} NEXT={self.next_header} HLIM={self.hop_limit})"
4953
)
5054

5155
@classmethod

xcloud/protocol/teredo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def convert_teredo_addr_to_endpoint(
3535
if not teredo_tuple:
3636
raise ValueError('Not a teredo address')
3737

38-
prefix, server_ipv4, flags, udp_port, client_ipv4 = \
38+
_, server_ipv4, flags, udp_port, client_ipv4 = \
3939
unpack('!IIHHI', teredo_addr)
4040

4141
# Deobfuscate/invert client address and port

xcloud/scripts/pcap_reader.py

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,63 @@
33
"""
44
import argparse
55
import logging
6+
from typing import Any, Optional
67

78
import dpkt
89
from aiortc import rtp
910
from aioice import stun
1011
from construct.lib import containers
1112

12-
from ..protocol import packets, teredo
13+
from ..protocol import packets, teredo, ipv6
1314

1415

1516
logging.basicConfig(level=logging.DEBUG)
1617
containers.setGlobalPrintFullStrings(True)
1718
LOG = logging.getLogger(__name__)
1819

19-
def print_stun(stun: stun.Message) -> None:
20-
print(f'STUN: {stun}')
20+
def get_info_stun(stun: stun.Message) -> None:
21+
return f'STUN: {stun}'
2122

22-
def print_rtp(rtp: rtp.RtpPacket) -> None:
23+
def get_info_rtp(rtp: rtp.RtpPacket) -> None:
2324
try:
2425
payload_name = packets.PayloadType(rtp.payload_type)
2526
except:
2627
payload_name = '<UNKNOWN>'
2728

28-
print(f'RTP: {payload_name.name} {rtp}')
29+
return f'RTP: {payload_name.name} {rtp}'
30+
31+
def get_info_teredo(teredo: teredo.TeredoPacket) -> None:
32+
info = f'TEREDO: {teredo}'
33+
if teredo.ipv6.next_header != ipv6.NO_NEXT_HEADER:
34+
data = teredo.ipv6.data
35+
if type(data) == bytes:
36+
raise ValueError(f'TEREDO contains unparsed-subpacket: {data}')
37+
subpacket_info = get_info_general(data)
38+
info += f'\n -> TEREDO-WRAPPED: {subpacket_info}'
39+
return info
2940

30-
def print_teredo(teredo: teredo.TeredoPacket) -> None:
31-
print(f'TEREDO: {teredo}')
3241

3342
PACKET_TYPES = [
34-
(stun.parse_message, print_stun),
35-
(rtp.RtpPacket.parse, print_rtp),
36-
(teredo.TeredoPacket.parse, print_teredo)
43+
(stun.parse_message, get_info_stun),
44+
(rtp.RtpPacket.parse, get_info_rtp),
45+
(teredo.TeredoPacket.parse, get_info_teredo)
3746
]
3847

48+
def get_info_general(packet: Any) -> Optional[str]:
49+
if isinstance(packet, dpkt.udp.UDP):
50+
data = bytes(packet.data)
51+
for cls, info_func in PACKET_TYPES:
52+
try:
53+
instance = cls(data)
54+
info = info_func(instance)
55+
return info
56+
except:
57+
pass
58+
elif isinstance(packet, bytes):
59+
return '<RAW BYTES>'
60+
else:
61+
return '<UNHANDLED>'
62+
3963
def packet_filter(filepath):
4064
with open(filepath, 'rb') as fh:
4165
for ts, buf in dpkt.pcap.Reader(fh):
@@ -46,23 +70,18 @@ def packet_filter(filepath):
4670
continue
4771

4872
ip = eth.data
49-
if not isinstance(ip.data, dpkt.udp.UDP):
73+
subpacket = ip.data
74+
if not isinstance(subpacket, dpkt.udp.UDP):
5075
continue
5176

52-
yield(ip.data, ts)
77+
yield(subpacket, ts)
5378

5479

5580
def parse_file(pcap_filepath: str) -> None:
5681
for packet, timestamp in packet_filter(pcap_filepath):
57-
packet = bytes(packet.data)
58-
for cls, print_func in PACKET_TYPES:
59-
try:
60-
instance = cls(packet)
61-
print_func(instance)
62-
except:
63-
#LOG.exception('Failed to parse')
64-
pass
65-
82+
info = get_info_general(packet)
83+
if info:
84+
print(info)
6685

6786
def main():
6887
parser = argparse.ArgumentParser(

0 commit comments

Comments
 (0)