The main purpose of this script is to generate a diagram such as Wireshark do with sip/rtp captures, obviously without the need to open Wireshark and using your mouse.
More over, it can be used to automatically generate diagrams from a bunch of pcap or directly in a web interface.
Whis this need and the desire to discover a little more python I tried to develop a script which is by the way not (I guess) the best way to achieve, but it works and this is what I want !
How it works
It uses mutiples “default” and “not default” python libraries :
- python3 : it’s better to run the script 😉
- git : if you want to clone directly from github
- tshark and pyshark : to manage packets
- markdown and md-mermaid : for drawing the diagram
Please note that it was tested successfully on Ubuntu 21.10 (my personnal laptop) and on a fresh Debian 11 virtual machine. It’s possible that I missed up some dependencies on Ubuntu because of some already present on my laptop (it should not I think).
Setup env
Install the tools named above
apt update
apt install git tshark python3-pip --no-install-recommends
pip3 install pyshark markdown md-mermaid
Then clone the github repo
git clone https://github.com/fulljackz/DrawMyCall.git
cd DrawMyCall
Here we are, we have a folder containing this stuff
├── drawmycall.py
├── html
│ ├── mermaid.css
│ ├── mermaid.min.js
│ └── sip-rtp-g722.pcap.html
├── img
│ ├── mermaid.png
│ ├── mermaid-time.png
│ └── wireshark.png
├── pcap_samples
│ ├── sip-rtp-g722.pcap
│ ├── sip-rtp-g729a.pcap
│ ├── sip-rtp-gsm.pcap
│ ├── sip-rtp-ilbc.pcap
│ ├── sip-rtp-lpc.pcap
│ └── sip-rtp-opus.pcap
└── README.md
- drawmycall.py is the script intersting us.
- ./html/ is the folder contaning the
.css
and.js
files producing thepcap.html
files. - ./img/ is a folder for documentation images.
- ./pcap_samples/ contains
.pcap
files for testing. They are directly available from wireshark wiki.
If you open the sip-rtp-g722.pcap.html
file in ./html/
folder you’ll have an overview of what the script can do :
Code notes
I didn’t want to have to deal with arguments manually, something had to exist for my need and I was right. Not sure if it is the niceset solution (once again), but as I said before : it works !
To deal with arguments and print help I did this :
if __name__ == "__main__":
parser = argparse.ArgumentParser()
# Show args as required : https://bugs.python.org/issue9694
req_grp = parser.add_argument_group(title='required arguments')
req_grp.add_argument("-f", "--file", required=True, help="path to your pcap file")
parser.add_argument("-t", "--time", help="Add time on diagram",
action="store_true")
args = parser.parse_args()
It is simple as the code. The only thing to note here is the required=True
for the --file
argument.
The script contains only a main function, it uses the pyshark library and parse packet per packet searching for call informations :
pcapFile = pyshark.FileCapture(capture)
# Parse .pcap
for num in pcapFile:
If the packet in the loop has rtp attribute and length > 100 (because of bad rtp packets) or sip attribute, it set a different separator (plain or dot line for merrmaid), and it saves some informations such as source ip, destination ip, rtp payload type, sip status etc.
# check if packet has rtp attribute
if hasattr(num, 'rtp') and int(num.length) >= 100:
diff = "-->"
diagSeq = [num['IP'].src, diff, num['IP'].dst, diff, num['RTP'].p_type.showname]
# check if packet has sip attribute
if hasattr(num, 'sip'):
diff = "->>"
if hasattr(num['sip'], 'status_line'):
status = num['sip'].status_line
else:
status = num['sip'].method
diagSeq = [num['IP'].src, diff, num['IP'].dst, diff, status]
To avoid multiples identical lines on the diagram, script makes a copy of diagSeq[] in sequences[] only if diagSeq[x] is not already in sequences[]
if diagSeq not in sequences:
sequences.append(diagSeq)
timestamp.append(num.frame_info.time_relative)
Then, it starts from the first value and loop over sequences[] array to build the diagram structure in markdown into mermaidMarkdown[].
If -t
option is set it add the time on the left.
Finally, it convert mermaidMarkdown[] array to mm string converted to html using the md_mermaid
extension.
y = sequences[0][0]
mermaidMarkdown.append("{} {}".format("\n~~~mermaid\n", "sequenceDiagram\n"))
for x in sequences:
mermaidMarkdown.append("{} {} {} {} {} {}".format(x[0], x[1], x[2], ":", x[4], "\n"))
if time:
mermaidMarkdown.append("{} {} {} {} {}".format("Note left of ", y, ":", timestamp[i], "\n"))
i+=1
mermaidMarkdown.append("{} {}".format("\n~~~\n", '<script src="./mermaid.min.js"></script>'))
mm = "".join(mermaidMarkdown)
html = markdown.markdown(mm, extensions=['md_mermaid'])
out.write(html)
out.close()
Give a try
The first thing we can try is the help function :
./drawmycall.py --help
usage: drawmycall.py [-h] -f FILE [-t]
optional arguments:
-h, --help show this help message and exit
-t, --time Add time on diagram
required arguments:
-f FILE, --file FILE path to your pcap file
Let’s generate a diagram with the ./pcap_samples/sip-rp-opus.pcap
, with wireshark :
And with drawmycall.py :
./drawmycall.py -f ./pcap_samples/sip-rtp-opus.pcap
Open ./html/sip-rtp-opus.pcap.html
Note : To avoid multiple rtp lines (which would be a mess), there is only one line showing the voice payloads.
If you need to get the time since first packet in your capture, add -t
option to the command line
./drawmycall.py -f ./pcap_samples/sip-rtp-opus.pcap -t
Which should output this html file, with time since first packet on the left
Enjoy 😉