33"""
44import argparse
55import logging
6+ from typing import Any , Optional
67
78import dpkt
89from aiortc import rtp
910from aioice import stun
1011from construct .lib import containers
1112
12- from ..protocol import packets , teredo
13+ from ..protocol import packets , teredo , ipv6
1314
1415
1516logging .basicConfig (level = logging .DEBUG )
1617containers .setGlobalPrintFullStrings (True )
1718LOG = 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
3342PACKET_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+
3963def 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
5580def 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
6786def main ():
6887 parser = argparse .ArgumentParser (
0 commit comments