This is a static archive of our old Q&A Site. Please post any new questions and answers at

How do you filter for duplicate RTP packets?


Can anyone identify a way to filter Duplicate RTP packets in WS? We are sniffing RTP packets on a workstation which are coming from a Cisco Cube and compiling them into an ASF file for Call Recording Evaluation purposes. The duplciate packets are causing problems for us and our network team is asking for evidence.

It took a lot of time to identify it in one of the WS captures but we showed the duplicate packet to them. The network and telephony teams now want numerous examples and we cannot find an easy way to identify duplicate RTP packets in the WS captures, only TCP. Ideas would be greatly appreciated.


This question is marked "community wiki".

asked 22 Dec '14, 12:43

swaisboy's gravatar image

accept rate: 0%

2 Answers:


Duplicate IP ID field values in the IP header would be one clear indicator of a duplicate packet. The system generating the initial IP packet typically increments that field with each successive packet, and no router should every modify it, so if you see two packets with the same IP ID field and the same content, that's a really strong indicator of a duplicate.

answered 22 Dec '14, 15:39

Quadratic's gravatar image

accept rate: 13%

edited 22 Dec '14, 15:40

Thanks Quadratic. We are able to identify the duplicate packets as you indicated above using similar methods, but we need help trying to Filter for all Duplicate RTP packets. There is a ton of data to parse through. We see there is a way to do that with TCP, but have not found a way to Filter specificlaly duplciate RTP packets. Thanks.

(22 Dec '14, 16:10) swaisboy

One method is simply to use editcap to filter them out. The '-d' option of editcap should do it if the duplicates are close together and truly identical (uses MD5 hash comparison to detect them):

In that example: editcap -d capture.pcap capture_without_duplicates.pcap

(22 Dec '14, 19:28) Quadratic


You could use a Lua script to do it.

For example the script below will create a fake "rtpdup" protocol for RTP packets, and set a new field called "rtpdup.duplicate" to true if it's a duplicate. That way you can filter on that field's value in Wireshark.

So just copy paste the below code into a new file with a .lua extension (e.g., "rtpdup.lua"), and put it in your Wireshark personal plugins directory; and then start Wireshark, load up your capture file, and use the display filter "rtpdup.duplicate == true", and voilà you'll only see duplicate RTP packets. This script uses the combination of IP ID field, RTP sequence number, and RTP SSRC field... all three must match for another packet to be considered a duplicate. (or you can reduce it by changing the Lua code... it's fairly straightforward)

-- our new Proto object
local rtpdup = Proto("rtpdup","RTP Duplicates Protocol")

– new fields for our "rtpdup" protocol – the purpose for these is so they can be filtered upon local pf_is_dup = ProtoField.bool("rtpdup.duplicate", "Duplicated") local pf_dup_frame = ProtoField.framenum("rtpdup.frame", "DupFrame", base.NONE)

– register the ProtoFields above rtpdup.fields = { pf_is_dup, pf_dup_frame }

– some existing fields we need to extract from RTP packets, to determine duplicates – all 3 of these must be the same for us to consider two packets duplicates local f_ip_id ="") local f_rtp_seq ="rtp.seq") local f_rtp_ssrc ="rtp.ssrc")

– the table we use to track seen packet #s and seen field info – we'll use this as both an array and map table – the array portion is indexed by packet number – the map portion is keyed by "" – the resultant for both is the same instance of a subtable with the – packet numbers of the dups in an array list local packets = {}

local function generateKey(…) local t = { … } return table.concat(t, ':') end

– adds the packet's number to both the array and map – which is done when we see a particular set of fields for the first time local function addPacketList(pnum, key) local list = { pnum } packets[key] = list packets[pnum] = list end

– adds the packet to the array part, using an existing list of dups – also adds the packet's number to the list of dups local function addPacket(pnum, list) – add this packet's number to the array portion of the big table packets[pnum] = list – add this packet's number to the list of dups list[#list + 1] = pnum end

– whenever a new capture file is opened, we want to reset our table – so we hook into the init() routine to do that function rtpdup.init() packets = {} end

– some forward "declarations" of helper functions we use in the dissector local createProtoTree

– our dissector function function rtpdup.dissector(tvb, pinfo, tree) – first, check if this is an rtp packet, by seeing if it has a rtp.seq local rtp_seq = select(1, f_rtp_seq())

if not rtp_seq then
    -- not an RTP packet

local pnum = pinfo.number

-- see if we've already processed this packet number
local list = packets[pnum]

if not list then
    -- haven't processed this packet
    -- see if the fields match another packet we've seen before
    local ip_id = select(1, f_ip_id())
    local rtp_ssrc = select(1, f_rtp_ssrc())
    local key = generateKey(tostring(ip_id), tostring(rtp_seq), tostring(rtp_ssrc))

    list = packets[key]

    if not list then
        -- haven't seen these fields before, so add it as a non-dup (so far)
        addPacketList(pnum, key)
        createProtoTree(pnum, tree)
        -- we haven't processed this packet, but we have seen the same fields
        -- so it's a duplicate.  Add its number to the array and entry...
        addPacket(pnum, list)
        -- and now create its tree
        createProtoTree(pnum, tree, list)
    -- we found the packet number already in the table, which means
    -- we've processed it before
    createProtoTree(pnum, tree, list)


createProtoTree = function (pnum, root, list) – add our "protocol" local tree = root:add(rtpdup)

if not list or #list < 2 then
    -- it's not a duplicate
    tree:add(pf_is_dup, false):set_generated()
    tree:add(pf_is_dup, true):set_generated()
    -- now add the other packet numbers as reference tree item fields
    for _, num in ipairs(list) do
        if num ~= pnum then
            tree:add(pf_dup_frame, num):set_generated()


– then we register rtpdup as a postdissector register_postdissector(rtpdup)

answered 23 Dec ‘14, 00:39

Hadriel's gravatar image

accept rate: 18%