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

How to Reassemble fragments in a dissector by fragment_add_seq_check function

1

hi, i have a protocol that is layered on top of UDP that splits up its own data stream. If a packet is bigger than some given size, it will be split into chunks. A flag byte that signals the presence of a multi-packet sequence and also the last packet, followed by an ID of the sequence and a packet sequence number. i do step by step like 1 but, the fragment_add_seq_check function always return 0. what is the problem? can any one help me? anything should be added to this example for reassemble correctly? my code is here:

    #include "epan/packet.h"
    #include "epan/reassemble.h"
    #define FOO_PORT 1234
    static int proto_foo = -1;
    static int hf_foo_fragmentation = -1;
    static int hf_foo_morefrag = -1;
    static int hf_foo_sequenceno = -1;
    static int hf_foo_sequenceid = -1;
    static reassembly_table msg_reassembly_table;
    static gint ett_foo = -1;
    static int hf_msg_fragments = -1;
    static int hf_msg_fragment = -1;
    static int hf_msg_fragment_overlap = -1;
    static int hf_msg_fragment_overlap_conflicts = -1;
    static int hf_msg_fragment_multiple_tails = -1;
    static int hf_msg_fragment_too_long_fragment = -1;
    static int hf_msg_fragment_error = -1;
    static int hf_msg_fragment_count = -1;
    static int hf_msg_reassembled_in = -1;
    static int hf_msg_reassembled_length = -1;
    static int hf_msg_reassembled_data=-1;
    static gint ett_msg_fragment = -1;
    static gint ett_msg_fragments = -1;
    static const fragment_items msg_frag_items = {
        /* Fragment subtrees */
        &ett_msg_fragment,
        &ett_msg_fragments,
        /* Fragment fields */
        &hf_msg_fragments,
        &hf_msg_fragment,
        &hf_msg_fragment_overlap,
        &hf_msg_fragment_overlap_conflicts,
        &hf_msg_fragment_multiple_tails,
        &hf_msg_fragment_too_long_fragment,
        &hf_msg_fragment_error,
        &hf_msg_fragment_count,
        &hf_msg_reassembled_in,
        /* Reassembled length field */
        &hf_msg_reassembled_length,
        &hf_msg_reassembled_data,
        "Message fragments"
    };
    static int
    dissect_foo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
    {
    gint offset = 0;
        col_set_str(pinfo->cinfo, COL_PROTOCOL, "FOO");
        col_clear(pinfo->cinfo,COL_INFO);
        proto_item *ti = proto_tree_add_item(tree, proto_foo, tvb, 0, -1, ENC_NA);
        proto_tree *foo_tree = proto_item_add_subtree(ti, ett_foo);
        guint8 fragmentation=tvb_get_guint8(tvb,offset);
        proto_tree_add_item(foo_tree, hf_foo_fragmentation, tvb, offset, 1, ENC_BIG_ENDIAN);
        offset += 1;
        guint8 morefrag=tvb_get_guint8(tvb,offset);
        proto_tree_add_item(foo_tree, hf_foo_morefrag, tvb, offset, 1, ENC_BIG_ENDIAN);
        offset += 1;
        guint8 sequenceno=tvb_get_guint8(tvb,offset);
        proto_tree_add_item(foo_tree, hf_foo_sequenceno, tvb, offset, 1, ENC_BIG_ENDIAN);
        offset += 1;
        guint8 sequenceid=tvb_get_guint8(tvb,offset);
        proto_tree_add_item(foo_tree, hf_foo_sequenceid, tvb, offset, 1, ENC_BIG_ENDIAN);
        offset += 1;
    gboolean save_fragmented = pinfo->fragmented;
    tvbuff_t *next_tvb;
    if (fragmentation) 
    {       tvbuff_t* new_tvb = NULL;
        fragment_head *frag_msg = NULL;
        pinfo->fragmented = TRUE;
        frag_msg = fragment_add_seq_check(&msg_reassembly_table,
            tvb, offset, pinfo,
            sequenceid, NULL, 
            sequenceno, 
            tvb_captured_length_remaining(tvb, offset),
            morefrag);
            new_tvb = process_reassembled_data(tvb, offset, pinfo,
            "Reassembled Message", frag_msg, &msg_frag_items,
            NULL, foo_tree);
        if (frag_msg) { /* Reassembled */
            col_append_str(pinfo->cinfo, COL_INFO,
                    " (Message Reassembled)");
        } else { /* Not last packet of reassembled Short Message */
            col_append_fstr(pinfo->cinfo, COL_INFO,
                    " (Message fragment %u)", foo_tree);
        }
        if (new_tvb) { /* take it all */
            next_tvb = new_tvb;
        } else { /* make a new subset */
            next_tvb = tvb_new_subset_remaining(tvb, offset);
        }
    }
    else { /* Not fragmented */
        next_tvb = tvb_new_subset_remaining(tvb, offset);
    }
    pinfo->fragmented = save_fragmented;
        return tvb_captured_length(tvb);
    }
    void
    proto_register_foo(void)
    {
        static hf_register_info hf[] = {
                { &hf_foo_fragmentation,
                { "FOO PDU Fragmentation", "foo.fragmentation",
                FT_UINT8, BASE_HEX,
                NULL, 0x0,
                NULL, HFILL }
            },
           { &hf_foo_morefrag,
            { "FOO PDU MoreFrag", "foo.more.frag",
            FT_UINT8, BASE_HEX,
            NULL, 0x0,
            NULL, HFILL }
        },

        { &hf_foo_sequenceno,
            { "FOO PDU Sequence Number", "foo.seqn",
            FT_UINT8, BASE_DEC,
            NULL, 0x0,
            NULL, HFILL }
        },

            { &hf_foo_sequenceid,
            { "FOO PDU Sequence ID", "foo.seqn.id",
            FT_UINT8, BASE_DEC,
            NULL, 0x0,
            NULL, HFILL }
        },
        {&hf_msg_fragments,
    {"Message fragments", "msg.fragments",
    FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
{&hf_msg_fragment,
    {"Message fragment", "msg.fragment",
    FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
{&hf_msg_fragment_overlap,
    {"Message fragment overlap", "msg.fragment.overlap",
    FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
{&hf_msg_fragment_overlap_conflicts,
    {"Message fragment overlapping with conflicting data",
    "msg.fragment.overlap.conflicts",
    FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
{&hf_msg_fragment_multiple_tails,
    {"Message has multiple tail fragments",
    "msg.fragment.multiple_tails",
    FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
{&hf_msg_fragment_too_long_fragment,
    {"Message fragment too long", "msg.fragment.too_long_fragment",
    FT_BOOLEAN, 0, NULL, 0x00, NULL, HFILL } },
{&hf_msg_fragment_error,
    {"Message defragmentation error", "msg.fragment.error",
    FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
{&hf_msg_fragment_count,
    {"Message fragment count", "msg.fragment.count",
    FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
{&hf_msg_reassembled_in,
    {"Reassembled in", "msg.reassembled.in",
    FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
{&hf_msg_reassembled_length,
    {"Reassembled length", "msg.reassembled.length",
    FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
{ &hf_msg_reassembled_data,
        { "Reassembled FOO Data", "foo.reassembled.data", FT_BYTES, BASE_NONE, NULL, 0x0,
            "The reassembled payload", HFILL }},


    };
    /* Setup protocol subtree array */
    static gint *ett[] = {
        &ett_foo,
        &ett_msg_fragment,
        &ett_msg_fragments
    };

    proto_foo = proto_register_protocol (
        "FOO Protocol", /* name       */
        "FOO",      /* short name */
        "foo"       /* abbrev     */
        );
   proto_register_field_array(proto_foo, hf, array_length(hf));
    proto_register_subtree_array(ett, array_length(ett));


    reassembly_table_register(&msg_reassembly_table,
        &addresses_ports_reassembly_table_functions);

}
void
proto_reg_handoff_foo(void)
{
    static dissector_handle_t foo_handle;

    foo_handle = create_dissector_handle(dissect_foo, proto_foo);
    dissector_add_uint("udp.port", FOO_PORT, foo_handle);
}</code></pre></div><div id="question-tags" class="tags-container tags"><span class="post-tag tag-link-fragment_add" rel="tag" title="see questions tagged &#39;fragment_add&#39;">fragment_add</span> <span class="post-tag tag-link-reassembly" rel="tag" title="see questions tagged &#39;reassembly&#39;">reassembly</span></div><div id="question-controls" class="post-controls"><div class="community-wiki">This question is marked "community wiki".</div></div><div class="post-update-info-container"><div class="post-update-info post-update-info-user"><p>asked <strong>07 Jun '17, 00:01</strong></p><img src="https://secure.gravatar.com/avatar/0b6bdfea45d7093830a2a0638a758239?s=32&amp;d=identicon&amp;r=g" class="gravatar" width="32" height="32" alt="hhw&#39;s gravatar image" /><p><span>hhw</span><br />

104711
accept rate: 100%

edited 11 Jun ‘17, 16:54

2

It would be useful to know how fragment_add_seq_check() is being called. In particular it would be useful to know what the values of the following parameters are for each call up to the final fragment (i.e., when reassembly should complete):

  • id
  • frag_number
  • more_frags

IIRC you really want to see something like:

  1. id=x,frag_number=0,more_frags=1
  2. id=x,frag_number=1,more_frags=1
  3. id=x,frag_number=2,more_frags=0 <– this should complete reassembly
(07 Jun ‘17, 19:02) JeffMorriss ♦
2

What is the value of morefrag when there are more fragments?

(12 Jun ‘17, 12:51) jpetersen

morefrag when there are more fragments is 1. if i have 3 packet the values are :

id=10,frag_number=1,more_frags=1

id=10,frag_number=2,more_frags=1

id=10,frag_number=3,more_frags=0 (<– this should complete reassembly)

(12 Jun ‘17, 23:59) hhw


One Answer:

1

[What happened to the earlier comment that had the more_frag output? It seems to have disappeared...]

Anyway, I missed this earlier, but just now I noticed that your frag_number starts at 1. According to the docs for fragment_add_seq():

/*
 * Like fragment_add, but fragments have a block sequence number starting from
 * zero (for the first fragment of each datagram). This differs from
 * fragment_add for which the fragment may start at any offset.

where fragment_add_seq_check() (which is what you're using) says:

/*
 * Like fragment_add_seq, but maintains a table for completed reassemblies
 * just like fragment_add_check.

IOW I think you either need to subtract one from your frag_numbers (so they start at 0) or you need to use fragment_add_check().

answered 13 Jun '17, 06:11

JeffMorriss's gravatar image

JeffMorriss ♦
6.2k572
accept rate: 27%

ok, thank you very much, my fragment may start at any offset so i can't subtract one from frag_numbers, i use fragment_add_check(), but it doesn't work. can you help me.

id=10,frag_number=10,more_frags=1
id=10,frag_number=11,more_frags=1
id=10,frag_number=12,more_frags=0 (<-- this should complete reassembly)
(14 Jun '17, 01:09) hhw