Ulf Lamping wrote:
Hmmm, unfortunately, I'm confused now. I understand what you're talking
about and I was already questioning myself *how* this "problem" is
handled in a any way.
However, in this case I don't understand what the more_frags flag is all
about, could someone explain (or even better explain it in the
reassemble.h) ...
Well, in the case of IP fragment reassembly, a fragmented IP datagram
consists of a number of fragments. Each fragment has a "fragment
offset" field, which is an offset, in bytes, from the beginning of the
fragmented datagram, of the data in the fragment.
All but the last of the fragments has the MF (More Fragments) flag set
in the IP header. All of the fragments have the same identification
field in the IP header.
IP reassembly is done by:
If an IP datagram with a fragment offset of 0 (meaning "first
fragment") and without the MF bit set (meaning "last fragment") is
received, this is a non-fragmented datagram, and there's no reassembly
to do; deliver the packet upstream.
Otherwise:
Search for an in-progress reassembly process with the specified
identification value.
If none is found, start one, and add the fragment to it.
If one is found, add the fragment to it. If the first fragment
(fragment with an offset of 0) is present, the last fragment (fragment
with MF not set) is present, and there are no unfilled "holes" in
between them (byte ranges within the fragment not covered by [fragment
offset, fragment offset + fragment length)), reassembly is done; put the
packet data together, and deliver the reassembled packet upstream.
What my problem is with the DCE/RPC defragmentation, connection oriented
TCP based (SMB works equally):
In the connection oriented DCE/RPC fragmentation (connectionless is
different here, as it uses sequence numbers), all packets are send in
sequence and there's *no* fragment offset inside the packet data, this
is handled by the byte position in the TCP stream.
There are three different forms of reassembly supported by reassemble.c:
1) IP-style reassembly, which is what fragment_add(),
fragment_add_multiple_ok(), and fragment_add_check() support, wherein
fragments can appear out of order, and fragments are tagged with a byte
offset;
2) another, similar style of reassembly, which is what
fragment_add_seq(), fragment_add_seq_check(), and
fragment_add_seq_802_11() support, where fragments can appear out of
order, and fragments are tagged with fragment numbers within a fragment
(starting at 0) rather than byte offsets;
3) fragment/segment reassembly for sequenced protocols - i.e.,
protocols such as TCP, COTP, NBF, etc. whose clients are delivered data
in order and thus where all packets, whether they're part of a
fragmented packet or not, have sequence numbers that are *not* relative
to the beginning of a fragment - which is what fragment_add_seq_next()
supports, where fragments *can't* appear out of order, and fragments
aren't tagged with any byte offset or sequence number.
For fragmentation atop a reliable, sequenced protocol,
fragment_add_seq_next() is the right routine to use. That means that if
fragments don't appear in order in the capture file, reassembly won't
work correctly - but, in that case, other things might not work
correctly, either, in that if the dissection of packet N+1 depends on
the dissection of packet N (given in-order delivery of packets, the
recipient of those packets can certainly make the *processing* of packet
N+1 depend on the results of processing packet N, so a protocol that
does in-order delivery, or a protocol running atop such a protocol, can
work that way), so the "right" fix for that would involve Ethereal
detecting an out-of-order packet and *not* handing it to subdissectors
until packets prior to it are seen.
We currently don't do that. An example of one scheme for that in action
- in this example, all packets in this protocol have a sequence number,
with the first packet in the connection having sequence number 0, and
this is the "first pass" (only pass, in the case of Tethereal);
packet 0 is seen by the dissector - being the first packet, it's
in-order by definition, and is handed to the subdissector, and the
dissector sets itself up to expect packet 1;
packet 2 is seen by the dissector, which sees that it's delivered out
of order - it dissects the header, but does nothing with the payload
other than saving it away, along with whatever information from the
header is necessary for the subdissector's use;
packet 1 is seen by the dissector, which is the "missing" packet - the
dissector hands that one to the subdissector, and then, when the
subdissector returns, the dissector constructs a tvbuff for the payload
of packet 2, and hands that to the subdissector.
If this protocol involves reassembly, "hands it to the subdissector"
becomes "does reassembly and, if a complete packet is available, hands
it to the subdissector".
However, as we're not doing that now, I'll just leave that as a thought
for later (I'll add it to one of the wish lists in the Wiki at some point).
What I've tried is to use the fragment total length as a way to keep the
current offset in the fragment data. The end of the last fragment must
be the offset of the next one. Assuming that the TCP dissector is
working correct, this would be a simple model and should work well.
Unfortunately, this doesn't work well with the reassemble code.
Any ideas how to solve this in a better way? Do we have other dissectors
doing a similar thing where I could have a look how I could solve this?
If a (current) inability to handle out-of-order packets is OK for the
connection-oriented DCE RPC dissector, using fragment_add_seq_next()
would probably be the right way to do reassembly.