Huge thanks to our Platinum Members Endace and LiveAction,
and our Silver Member Veeam, for supporting the Wireshark Foundation and project.

Wireshark-users: Re: [Wireshark-users] tshark: How to capture SNMP traps (UDP port 162) that migh

From: Guy Harris <guy@xxxxxxxxxxxx>
Date: Thu, 13 Dec 2012 12:44:50 -0800
On Dec 13, 2012, at 1:13 AM, Peter Valdemar Mørch <peter@xxxxxxxxx> wrote:

> We want to capture SNMP traps. The simple 
> 
>     tshark -f 'port 162'
> 
> Doesn't work if there are SNMP traps that are fragmented, because then we don't get all the fragments. I understand.
> 
> Wireshark now since rev 41216 saves all dependent packets too when one saves all packets according to the display filter [1] [2]. I've tried wireshark's version 1.8.2 and it works as described.
> 
> I therefore expected this to work for tshark 1.8.2 too:
> 
>     tshark -f udp -w alludp.pcap
>     # wait for it, wait for it...
>     tshark -r alludp.pcap -R snmp -w snmp.pcap
> 
> But it doesn't work. I only get one packet - it doesn't save all fragments. Two questions:
> 
> 1) Isn't the tshark command above the tshark equivalent of the same use case?

No.

"-f" specifies a capture filter, not a display filter.  The TShark command in question is the TShark equivalent of capturing, in Wireshark, with a *capture* filter of "udp", and then, when the capture is finished, applying a display filter of "snmp".

> 2) Is there some other way to capture exactly SNMP traps (UDP port 162) including fragmented ones with tshark avoiding having to install and start up wireshark?

There isn't a way to capture exactly SNMP traps, including fragmented ones, with *any* tool, using libpcap/WinPcap-style stateless filtering to filter out everything except for the SNMP traps; that includes Wireshark.

In order to filter all packets going to or from port 162, including fragments, a form of stateful filtering is necessary.

If a first fragment is seen with a UDP packet to or from port 162, the filtering mechanism would need to remember its IP ID, and check all non-first fragments for that IP ID and accept them as well.  That IP ID should probably expire after some amount of time after the first fragment is received; perhaps it should be removed if all the fragments of the packet have been seen and accepted.

If a fragment is seen for which no first fragment ID has been seen, that's harder - there is no guarantee that fragments arrive in order, and, in fact, I think some versions of Linux sent out fragments in *reverse* order, so that the receiver would see the last fragment first and would thus know how big the entire packet would be, and, in that case, could pre-allocate a buffer for the reassembled fragment.  For that one, you'd have to hold onto fragments for which the first fragment ID hadn't been seen, and deliver them if and when the first fragment arrives and it's accepted by the filter; doing that then either means delivering packets out of time order (which would be a bit annoying), deferring the delivery of packets that arrive following the offending non-first fragments until after they're delivered (which would be a bit annoying and would require a fair bit of buffering space - possibly in the kernel, as that's where the capture filtering is done in most OSes on which tcpdump/WinDump/*Shark run) or, at some layer after the filtering, buffering and sorting packets by their time stamps.

In the case of Wireshark, you're doing stateful filtering, but that's done *after* capturing the raw packets.  What you're doing is probably capturing all packets or, at least, capturing all IP packets (depending on what *capture* filter you specified when doing the capture), and, *after* you've done the capturing, and Wireshark has read the entire file and done all the reassembly of fragmented IP datagrams, and thus built the necessary state, filtering out all but the SNMP packets and then saving the packets.

The closest equivalent in TShark would be to first do:

	tshark -f {capture filter} -w unfiltered.pcap

where {capture filter} is whatever capture filter you used when doing the capture in Wireshark - if you left the capture filter blank, leave the -f flag out - and then doing

	tshark -2 -r unfiltered.pcap -R snmp -w snmp.pcap

which causes TShark to read unfiltered.pcap and process all the packets, so it does a reassembly of all fragmented packets, and then read it *again*, with a read filter of "snmp", and write the matching packets to the output file.

However, I don't think that code path has been changed to support writing "related" packets, and it might also apply the read filter on the *first* pass (and thus filter out the fragments), so it might not work.

TShark could certainly be *made* to support that, with a two-pass operation, but it might not do so currently.  That would involve not applying the read filter on the first pass, if we're currently doing so (that's probably something we should do unconditionally), and having -R divide packets into three categories - matched, didn't match but are part of a packet that did match, and didn't match and aren't part of a packet that did match - and have the packet-writing code path write out packets in the first two categories.