1"""
2Real-time transport protocol (RTP) capture plugin
3"""
4
5import datetime
6
7import dshell.core
8from dshell.output.alertout import AlertOutput
9
10from pypacker.layer4 import udp
11from pypacker.layer567 import rtp
12
13class DshellPlugin(dshell.core.PacketPlugin):
14
15    def __init__(self):
16        super().__init__(
17            name="RTP",
18            author="mm/dev195",
19            bpf="udp",
20            description="Real-time transport protocol (RTP) capture plugin",
21            longdescription="""
22The real-time transport protocol (RTP) plugin will extract the Hosts, Payload Type, Synchronization source,
23Sequence Number, Padding, Marker and Client MAC address from every RTP packet found in the given pcap.
24
25General usage:
26
27    decode -d rtp <pcap>
28    decode -d rtp --no-vlan --layer2=sll.SLL <pcap>
29
30Examples:
31
32    https://wiki.wireshark.org/SampleCaptures#SIP_and_RTP
33    https://wiki.wireshark.org/SampleCaptures?action=AttachFile&do=get&target=rtp_example.raw.gz
34
35    decode -d rtp rtp_example.pcap
36
37Output:
38
39    rtp 2016-09-21 23:44:40   50.197.16.141:1195  --     192.168.9.12:44352 **
40        From: 50.197.16.141 (00:02:31:11:a5:97) to 192.168.9.12 (45:20:01:31:45:40)
41        Payload Type (7 bits): Dynamic
42        Sequence Number (16 bits): 58635
43        Timestamp (32 bits): 1331328074
44        Synchronization source (32 bits): 1948709792
45        Arrival Time: 1474497880.6 --> 2016-09-21 22:44:40.604135
46        Contributing source (32 bits): 1, Padding (1 bit): 1, Extension (1 bit): 1, Marker (1 bit): 0
47     **
48    rtp 2016-09-21 23:44:40         10.5.1.8:5086  --         10.5.1.7:5070  **
49        From: 10.5.1.8 (00:02:81:11:a0:d7) to 10.5.1.7 (45:00:20:c8:a3:26)
50        Payload Type (7 bits): PCMU - Audio - 8000 Hz - 1 Channel
51        Sequence Number (16 bits): 17664
52        Timestamp (32 bits): 98240
53        Synchronization source (32 bits): 1671095215
54        Arrival Time: 1474497880.6 --> 2016-09-21 22:44:40.604160
55        Contributing source (32 bits): 0, Padding (1 bit): 0, Extension (1 bit): 0, Marker (1 bit): 0
56     **
57  """,
58            output=AlertOutput(label=__name__)
59        )
60
61    def premodule(self):
62        self.payload_type = {0: "PCMU - Audio - 8000 Hz - 1 Channel", 1: "Reserved", 2: "Reserved", 3: "GSM - Audio - 8000 Hz - 1 Channel",
63                             4: "G723 - Audio - 8000 Hz - 1 Channel", 5: "DVI4 - Audio - 8000 Hz - 1 Channel", 6: "DVI4 - Audio - 16000 Hz - 1 Channel",
64                             7: "LPC - Audio - 8000 Hz - 1 Channel", 8: "PCMA - Audio - 8000 Hz - 1 Channel", 9: "G722 - Audio - 8000 Hz - 1 Channel",
65                             10: "L16 - Audio - 44100 Hz - 2 Channel", 11: "L16 - Audio - 44100 Hz - 1 Channel", 12: "QCELP - Audio - 8000 Hz - 1 Channel",
66                             13: "CN - Audio - 8000 Hz - 1 Channel", 14: "MPA - Audio - 90000 Hz", 15: "G728 - Audio - 8000 Hz - 1 Channel", 16: "DVI4 - Audio - 11025 Hz - 1 Channel",
67                             17: "DVI4 - Audio - 22050 Hz - 1 Channel", 18: "G729 - Audio - 8000 Hz - 1 Channel", 19: "Reserved - Audio", 20: "Unassigned - Audio",
68                             21: "Unassigned - Audio", 22: "Unassigned - Audio", 23: "Unassigned - Audio", 24: "Unassigned - Video", 25: "CelB - Video - 90000 Hz",
69                             26: "JPEG - Video - 90000 Hz", 27: "Unassigned - Video", 28: "nv - Video - 90000 Hz", 29: "Unassigned - Video", 30: "Unassigned - Video",
70                             31: "H261 - Video - 90000 Hz", 32: "MPV - Video - 90000 Hz", 33: "MP2T - Audio/Video - 90000 Hz", 34: "H263 - Video - 90000 Hz"}
71
72        for i in range(35,72):
73            self.payload_type[i] = "Unassigned"
74        for i in range(72,77):
75            self.payload_type[i] = "Reserved for RTCP conflict avoidance"
76        for i in range(77,96):
77            self.payload_type[i] = "Unassigned"
78        for i in range(96,128):
79            self.payload_type[i] = "Dynamic"
80
81    def packet_handler(self, pkt):
82        # Scrape out the UDP layer of the packet
83        udpp = pkt.pkt.upper_layer
84        while not isinstance(udpp, udp.UDP):
85            try:
86                udpp = udpp.upper_layer
87            except AttributeError:
88                # There doesn't appear to be an UDP layer
89                return
90
91        # Parse the RTP protocol from above the UDP layer
92        rtpp = rtp.RTP(udpp.body_bytes)
93
94        if rtpp.version != 2:
95            # RTP should always be version 2
96            return
97
98        pt = self.payload_type.get(rtpp.pt, "??")
99
100        self.write("\n\tFrom: {0} ({1}) to {2} ({3}) \n\tPayload Type (7 bits): {4}\n\tSequence Number (16 bits): {5}\n\tTimestamp (32 bits): {6} \n\tSynchronization source (32 bits): {7}\n\tArrival Time: {8} --> {9}\n\tContributing source (32 bits): {10}, Padding (1 bit): {11}, Extension (1 bit): {12}, Marker (1 bit): {13}\n".format(
101            pkt.sip, pkt.smac, pkt.dip, pkt.dmac, pt, rtpp.seq, rtpp.ts,
102            rtpp.ssrc, pkt.ts, datetime.datetime.utcfromtimestamp(pkt.ts),
103            rtpp.cc, rtpp.p, rtpp.x, rtpp.m), **pkt.info())
104
105        return pkt
106