diff options
Diffstat (limited to 'epan/reassemble_test.c')
-rw-r--r-- | epan/reassemble_test.c | 1057 |
1 files changed, 1057 insertions, 0 deletions
diff --git a/epan/reassemble_test.c b/epan/reassemble_test.c new file mode 100644 index 0000000000..8f48946684 --- /dev/null +++ b/epan/reassemble_test.c @@ -0,0 +1,1057 @@ +/* Standalone program to test functionality of reassemble.h API + * + * These aren't particularly complete - they just test a few corners of + * functionality which I was interested in. In particular, they only test the + * fragment_add_seq_* (ie, FD_BLOCKSEQUENCE) family of routines. However, + * hopefully they will inspire people to write additional tests, and provide a + * useful basis on which to do so. + * + * $Id$ + * + * Copyright (c) 2007 MX Telecom Ltd. <richardv@mxtelecom.com> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <glib.h> + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <epan/emem.h> +#include <epan/packet.h> +#include <epan/packet_info.h> +#include <epan/proto.h> +#include <epan/tvbuff.h> +#include <epan/reassemble.h> + +#include <epan/dissectors/packet-dcerpc.h> + +#define ASSERT(b) do_test((b),"Assertion failed at line %i: %s\n", __LINE__, #b) +#define ASSERT_EQ(exp,act) do_test((exp)==(act),"Assertion failed at line %i: %s==%s (%i==%i)\n", __LINE__, #exp, #act, exp, act) +#define ASSERT_NE(exp,act) do_test((exp)!=(act),"Assertion failed at line %i: %s!=%s (%i!=%i)\n", __LINE__, #exp, #act, exp, act) + +int failure = 0; + +void do_test(int condition, char *format, ...) +{ + va_list ap; + + if(condition) + return; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + failure = 1; + + /* many of the tests assume this routine doesn't return on failure; if we + * do, it may provide more information, but may cause a segfault. Uncomment + * this line if you wish. + */ + exit(1); +} + +#define DATA_LEN 256 + +char *data; +tvbuff_t *tvb; +packet_info pinfo; + +/* fragment_table maps from datagram ids to head of fragment_data list + reassembled_table maps from <packet number,datagram id> to head of + fragment_data list */ +GHashTable *fragment_table = NULL, *reassembled_table = NULL; + +/********************************************************************************** + * + * fragment_add_seq + * + *********************************************************************************/ + +/* Simple test case for fragment_add_seq. + * Adds three fragments (out of order, with one for a different datagram in between), + * and checks that they are reassembled correctly. + */ +static void test_simple_fragment_add_seq(void) +{ + fragment_data *fd_head, *fdh0; + + printf("Starting test test_simple_fragment_add_seq\n"); + + pinfo.fd->num = 1; + fd_head=fragment_add_seq(tvb, 10, &pinfo, 12, fragment_table, + 0, 50, TRUE); + + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(NULL,fd_head); + + /* adding the same fragment again should do nothing, even with different + * offset etc */ + pinfo.fd->flags.visited = 1; + fd_head=fragment_add_seq(tvb, 5, &pinfo, 12, fragment_table, + 0, 60, TRUE); + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(NULL,fd_head); + + /* start another pdu (just to confuse things) */ + pinfo.fd->flags.visited = 0; + pinfo.fd->num = 2; + fd_head=fragment_add_seq(tvb, 15, &pinfo, 13, fragment_table, + 0, 60, TRUE); + ASSERT_EQ(2,g_hash_table_size(fragment_table)); + ASSERT_EQ(NULL,fd_head); + + /* now we add the terminal fragment of the first datagram */ + pinfo.fd->num = 3; + fd_head=fragment_add_seq(tvb, 5, &pinfo, 12, fragment_table, + 2, 60, FALSE); + + /* we haven't got all the fragments yet ... */ + ASSERT_EQ(2,g_hash_table_size(fragment_table)); + ASSERT_EQ(NULL,fd_head); + + /* finally, add the missing fragment */ + pinfo.fd->num = 4; + fd_head=fragment_add_seq(tvb, 15, &pinfo, 12, fragment_table, + 1, 60, TRUE); + + ASSERT_EQ(2,g_hash_table_size(fragment_table)); + ASSERT_NE(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(0,fd_head->frame); /* unused */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(170,fd_head->len); /* the length of data we have */ + ASSERT_EQ(2,fd_head->datalen); /* seqno of the last fragment we have */ + ASSERT_EQ(4,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET,fd_head->flags); + ASSERT_NE(NULL,fd_head->data); + ASSERT_NE(NULL,fd_head->next); + + ASSERT_EQ(1,fd_head->next->frame); + ASSERT_EQ(0,fd_head->next->offset); /* seqno */ + ASSERT_EQ(50,fd_head->next->len); /* segment length */ + ASSERT_EQ(0,fd_head->next->flags); + ASSERT_EQ(NULL,fd_head->next->data); + ASSERT_NE(NULL,fd_head->next->next); + + ASSERT_EQ(4,fd_head->next->next->frame); + ASSERT_EQ(1,fd_head->next->next->offset); /* seqno */ + ASSERT_EQ(60,fd_head->next->next->len); /* segment length */ + ASSERT_EQ(0,fd_head->next->next->flags); + ASSERT_EQ(NULL,fd_head->next->next->data); + ASSERT_NE(NULL,fd_head->next->next->next); + + ASSERT_EQ(3,fd_head->next->next->next->frame); + ASSERT_EQ(2,fd_head->next->next->next->offset); /* seqno */ + ASSERT_EQ(60,fd_head->next->next->next->len); /* segment length */ + ASSERT_EQ(0,fd_head->next->next->next->flags); + ASSERT_EQ(NULL,fd_head->next->next->next->data); + ASSERT_EQ(NULL,fd_head->next->next->next->next); + + /* test the actual reassembly */ + ASSERT(!memcmp(fd_head->data,data+10,50)); + ASSERT(!memcmp(fd_head->data+50,data+15,60)); + ASSERT(!memcmp(fd_head->data+110,data+5,60)); + + /* what happens if we revisit the packets now? */ + fdh0 = fd_head; + pinfo.fd->flags.visited = 1; + pinfo.fd->num = 1; + fd_head=fragment_add_seq(tvb, 10, &pinfo, 12, fragment_table, + 0, 50, TRUE); + /* + * this api relies on the caller to check fd_head -> reassembled_in + * + * Redoing all the tests seems like overkill - just check the pointer + */ + ASSERT_EQ(fdh0,fd_head); + + pinfo.fd->num = 3; + fd_head=fragment_add_seq(tvb, 5, &pinfo, 12, fragment_table, + 2, 60, FALSE); + ASSERT_EQ(fdh0,fd_head); + + pinfo.fd->num = 4; + fd_head=fragment_add_seq(tvb, 15, &pinfo, 12, fragment_table, + 1, 60, TRUE); + ASSERT_EQ(fdh0,fd_head); +} + +/* XXX ought to have some tests for overlapping fragments */ + +/* This tests the functionality of fragment_set_partial_reassembly for + * FD_BLOCKSEQUENCE reassembly. + * + * We add a sequence of fragments thus: + * seqno frame offset len (initial) more_frags + * ----- ----- ------ --- -------------------- + * 0 1 10 50 false + * 1 2 0 40 true + * 1 3 0 40 true (a duplicate fragment) + * 2 4 20 100 false + * 3 5 0 40 false + */ +static void test_fragment_add_seq_partial_reassembly(void) +{ + fragment_data *fd_head, *fd; + + printf("Starting test test_fragment_add_seq_partial_reassembly\n"); + + /* generally it's probably fair to assume that we will be called with + * more_frags=FALSE. + */ + pinfo.fd->num = 1; + fd_head=fragment_add_seq(tvb, 10, &pinfo, 12, fragment_table, + 0, 50, FALSE); + + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_NE(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(0,fd_head->frame); /* unused */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(50,fd_head->len); /* the length of data we have */ + ASSERT_EQ(0,fd_head->datalen); /* seqno of the last fragment we have */ + ASSERT_EQ(1,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET,fd_head->flags); + ASSERT_NE(NULL,fd_head->data); + ASSERT_NE(NULL,fd_head->next); + + ASSERT_EQ(1,fd_head->next->frame); + ASSERT_EQ(0,fd_head->next->offset); /* seqno */ + ASSERT_EQ(50,fd_head->next->len); /* segment length */ + ASSERT_EQ(0,fd_head->next->flags); + ASSERT_EQ(NULL,fd_head->next->data); + ASSERT_EQ(NULL,fd_head->next->next); + + /* test the actual reassembly */ + ASSERT(!memcmp(fd_head->data,data+10,50)); + + /* now we announce that the reassembly wasn't complete after all. */ + fragment_set_partial_reassembly(&pinfo,12,fragment_table); + + /* and add another segment. To mix things up slightly (and so that we can + * check on the state of things), we're going to set the more_frags flag + * here + */ + pinfo.fd->num = 2; + fd_head=fragment_add_seq(tvb, 0, &pinfo, 12, fragment_table, + 1, 40, TRUE); + + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(NULL,fd_head); + + fd_head=fragment_get(&pinfo,12,fragment_table); + ASSERT_NE(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(0,fd_head->frame); /* unused */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + /* ASSERT_EQ(50,fd_head->len); the length of data we have */ + ASSERT_EQ(0,fd_head->datalen); /* seqno of the last fragment we have */ + ASSERT_EQ(0,fd_head->reassembled_in); + ASSERT_EQ(FD_BLOCKSEQUENCE,fd_head->flags); + ASSERT_NE(NULL,fd_head->data); + ASSERT_NE(NULL,fd_head->next); + + fd=fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); /* seqno */ + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(FD_NOT_MALLOCED,fd->flags); + ASSERT_EQ(fd_head->data,fd->data); + ASSERT_NE(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(1,fd->offset); /* seqno */ + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_NE(NULL,fd->data); + ASSERT_EQ(NULL,fd->next); + + /* Another copy of the second segment. + */ + pinfo.fd->num = 3; + fd_head=fragment_add_seq(tvb, 0, &pinfo, 12, fragment_table, + 1, 40, TRUE); + + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(NULL,fd_head); + fd_head=fragment_get(&pinfo,12,fragment_table); + ASSERT_NE(NULL,fd_head); + ASSERT_EQ(0,fd_head->frame); /* unused */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + /* ASSERT_EQ(50,fd_head->len); the length of data we have */ + ASSERT_EQ(0,fd_head->datalen); /* seqno of the last fragment we have */ + ASSERT_EQ(0,fd_head->reassembled_in); + ASSERT_EQ(FD_BLOCKSEQUENCE,fd_head->flags); + ASSERT_NE(NULL,fd_head->data); + ASSERT_NE(NULL,fd_head->next); + + fd=fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); /* seqno */ + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(FD_NOT_MALLOCED,fd->flags); + ASSERT_EQ(fd_head->data,fd->data); + ASSERT_NE(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(1,fd->offset); /* seqno */ + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_NE(NULL,fd->data); + ASSERT_NE(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(1,fd->offset); /* seqno */ + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_NE(NULL,fd->data); + ASSERT_EQ(NULL,fd->next); + + + + /* have another go at wrapping things up */ + pinfo.fd->num = 4; + fd_head=fragment_add_seq(tvb, 20, &pinfo, 12, fragment_table, + 2, 100, FALSE); + + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_NE(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(0,fd_head->frame); /* unused */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(190,fd_head->len); /* the length of data we have */ + ASSERT_EQ(2,fd_head->datalen); /* seqno of the last fragment we have */ + ASSERT_EQ(4,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags); + ASSERT_NE(NULL,fd_head->data); + ASSERT_NE(NULL,fd_head->next); + + fd=fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); /* seqno */ + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ(NULL,fd->data); + ASSERT_NE(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(1,fd->offset); /* seqno */ + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ(NULL,fd->data); + ASSERT_NE(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(1,fd->offset); /* seqno */ + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(FD_OVERLAP,fd->flags); + ASSERT_EQ(NULL,fd->data); + ASSERT_NE(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(2,fd->offset); /* seqno */ + ASSERT_EQ(100,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ(NULL,fd->data); + ASSERT_EQ(NULL,fd->next); + + /* test the actual reassembly */ + ASSERT(!memcmp(fd_head->data,data+10,50)); + ASSERT(!memcmp(fd_head->data+50,data,40)); + ASSERT(!memcmp(fd_head->data+90,data+20,100)); + + + /* do it again (this time it is more complicated, with an overlap in the + * reassembly) */ + + fragment_set_partial_reassembly(&pinfo,12,fragment_table); + + pinfo.fd->num = 5; + fd_head=fragment_add_seq(tvb, 0, &pinfo, 12, fragment_table, + 3, 40, FALSE); + + fd_head=fragment_get(&pinfo,12,fragment_table); + ASSERT_NE(NULL,fd_head); + ASSERT_EQ(0,fd_head->frame); /* unused */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(230,fd_head->len); /* the length of data we have */ + ASSERT_EQ(3,fd_head->datalen); /* seqno of the last fragment we have */ + ASSERT_EQ(5,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET|FD_OVERLAP,fd_head->flags); + ASSERT_NE(NULL,fd_head->data); + ASSERT_NE(NULL,fd_head->next); + + fd=fd_head->next; + ASSERT_EQ(1,fd->frame); + ASSERT_EQ(0,fd->offset); /* seqno */ + ASSERT_EQ(50,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ(NULL,fd->data); + ASSERT_NE(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(2,fd->frame); + ASSERT_EQ(1,fd->offset); /* seqno */ + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ(NULL,fd->data); + ASSERT_NE(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(3,fd->frame); + ASSERT_EQ(1,fd->offset); /* seqno */ + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(FD_OVERLAP,fd->flags); + ASSERT_EQ(NULL,fd->data); + ASSERT_NE(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(4,fd->frame); + ASSERT_EQ(2,fd->offset); /* seqno */ + ASSERT_EQ(100,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ(NULL,fd->data); + ASSERT_NE(NULL,fd->next); + + fd=fd->next; + ASSERT_EQ(5,fd->frame); + ASSERT_EQ(3,fd->offset); /* seqno */ + ASSERT_EQ(40,fd->len); /* segment length */ + ASSERT_EQ(0,fd->flags); + ASSERT_EQ(NULL,fd->data); + ASSERT_EQ(NULL,fd->next); + + /* test the actual reassembly */ + ASSERT(!memcmp(fd_head->data,data+10,50)); + ASSERT(!memcmp(fd_head->data+50,data,40)); + ASSERT(!memcmp(fd_head->data+90,data+20,100)); + ASSERT(!memcmp(fd_head->data+190,data,40)); +} + +/********************************************************************************** + * + * fragment_add_dcerpc_dg + * + *********************************************************************************/ + +/* This can afford to be reasonably minimal, as it's just the same logic with a + * different hash key to fragment_add_seq + */ +static void test_fragment_add_dcerpc_dg(void) +{ + e_uuid_t act_id = {1,2,3,{4,5,6,7,8,9,10,11}}; + + fragment_data *fd_head, *fdh0; + GHashTable *fragment_table = NULL; + + printf("Starting test test_fragment_add_dcerpc_dg\n"); + + /* we need our own fragment table */ + dcerpc_fragment_table_init(&fragment_table); + fd_head=fragment_add_dcerpc_dg(tvb, 10, &pinfo, 12, &act_id, fragment_table, + 0, 50, TRUE); + + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(NULL,fd_head); + + /* start another pdu (just to confuse things) */ + pinfo.fd->num = 2; + fd_head=fragment_add_dcerpc_dg(tvb, 15, &pinfo, 13, &act_id, fragment_table, + 0, 60, TRUE); + ASSERT_EQ(2,g_hash_table_size(fragment_table)); + ASSERT_EQ(NULL,fd_head); + + /* another pdu, with the same fragment_id, but a different act_id, to the + * first one */ + pinfo.fd->num = 3; + act_id.Data1=2; + fd_head=fragment_add_dcerpc_dg(tvb, 15, &pinfo, 12, &act_id, fragment_table, + 0, 60, TRUE); + ASSERT_EQ(3,g_hash_table_size(fragment_table)); + ASSERT_EQ(NULL,fd_head); + act_id.Data1=1; + + /* now we add the terminal fragment of the first datagram */ + pinfo.fd->num = 4; + fd_head=fragment_add_dcerpc_dg(tvb, 5, &pinfo, 12, &act_id, fragment_table, + 1, 60, FALSE); + + ASSERT_EQ(3,g_hash_table_size(fragment_table)); + ASSERT_NE(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(0,fd_head->frame); /* unused */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(110,fd_head->len); /* the length of data we have */ + ASSERT_EQ(1,fd_head->datalen); /* seqno of the last fragment we have */ + ASSERT_EQ(4,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET,fd_head->flags); + ASSERT_NE(NULL,fd_head->data); + ASSERT_NE(NULL,fd_head->next); + + /* test the actual reassembly */ + ASSERT(!memcmp(fd_head->data,data+10,50)); + ASSERT(!memcmp(fd_head->data+50,data+5,60)); + + /* what happens if we revisit the packets now? */ + fdh0 = fd_head; + pinfo.fd->flags.visited = 1; + pinfo.fd->num = 1; + fd_head=fragment_add_dcerpc_dg(tvb, 10, &pinfo, 12, &act_id, fragment_table, + 0, 50, TRUE); + /* + * this api relies on the caller to check fd_head -> reassembled_in + * + * Redoing all the tests seems like overkill - just check the pointer + */ + ASSERT_EQ(fdh0,fd_head); +} + +/********************************************************************************** + * + * fragment_add_seq_check + * + *********************************************************************************/ + + +/* This routine is used for both fragment_add_seq_802_11 and + * fragment_add_seq_check. + * + * Adds a couple of out-of-order fragments and checks their reassembly. + */ +static void test_fragment_add_seq_check_work( + fragment_data *(*fn)(tvbuff_t *, int, packet_info *, guint32, GHashTable *, + GHashTable *, guint32, guint32, gboolean)) +{ + fragment_data *fd_head; + + pinfo.fd -> num = 1; + fd_head=fn(tvb, 10, &pinfo, 12, fragment_table, + reassembled_table, 0, 50, TRUE); + + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(0,g_hash_table_size(reassembled_table)); + ASSERT_EQ(NULL,fd_head); + + /* start another pdu (just to confuse things) */ + pinfo.fd->num = 2; + fd_head=fn(tvb, 15, &pinfo, 13, fragment_table, + reassembled_table, 0, 60, TRUE); + ASSERT_EQ(2,g_hash_table_size(fragment_table)); + ASSERT_EQ(0,g_hash_table_size(reassembled_table)); + ASSERT_EQ(NULL,fd_head); + + /* add the terminal fragment of the first datagram */ + pinfo.fd->num = 3; + fd_head=fn(tvb, 5, &pinfo, 12, fragment_table, + reassembled_table, 2, 60, FALSE); + + /* we haven't got all the fragments yet ... */ + ASSERT_EQ(2,g_hash_table_size(fragment_table)); + ASSERT_EQ(0,g_hash_table_size(reassembled_table)); + ASSERT_EQ(NULL,fd_head); + + /* finally, add the missing fragment */ + pinfo.fd->num = 4; + fd_head=fn(tvb, 15, &pinfo, 12, fragment_table, + reassembled_table, 1, 60, TRUE); + + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(3,g_hash_table_size(reassembled_table)); + ASSERT_NE(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(0,fd_head->frame); /* unused */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(170,fd_head->len); /* the length of data we have */ + ASSERT_EQ(2,fd_head->datalen); /* seqno of the last fragment we have */ + ASSERT_EQ(4,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET,fd_head->flags); + ASSERT_NE(NULL,fd_head->data); + ASSERT_NE(NULL,fd_head->next); + + ASSERT_EQ(1,fd_head->next->frame); + ASSERT_EQ(0,fd_head->next->offset); /* seqno */ + ASSERT_EQ(50,fd_head->next->len); /* segment length */ + ASSERT_EQ(0,fd_head->next->flags); + ASSERT_EQ(NULL,fd_head->next->data); + ASSERT_NE(NULL,fd_head->next->next); + + ASSERT_EQ(4,fd_head->next->next->frame); + ASSERT_EQ(1,fd_head->next->next->offset); /* seqno */ + ASSERT_EQ(60,fd_head->next->next->len); /* segment length */ + ASSERT_EQ(0,fd_head->next->next->flags); + ASSERT_EQ(NULL,fd_head->next->next->data); + ASSERT_NE(NULL,fd_head->next->next->next); + + ASSERT_EQ(3,fd_head->next->next->next->frame); + ASSERT_EQ(2,fd_head->next->next->next->offset); /* seqno */ + ASSERT_EQ(60,fd_head->next->next->next->len); /* segment length */ + ASSERT_EQ(0,fd_head->next->next->next->flags); + ASSERT_EQ(NULL,fd_head->next->next->next->data); + ASSERT_EQ(NULL,fd_head->next->next->next->next); + + /* test the actual reassembly */ + ASSERT(!memcmp(fd_head->data,data+10,50)); + ASSERT(!memcmp(fd_head->data+50,data+15,60)); + ASSERT(!memcmp(fd_head->data+110,data+5,60)); +} + +/* Simple test case for fragment_add_seq_check + */ +static void test_fragment_add_seq_check(void) +{ + printf("Starting test test_fragment_add_seq_check\n"); + + test_fragment_add_seq_check_work(fragment_add_seq_check); +} + + +/* This tests the case that the 802.11 hack does something different for: when + * the terminal segment in a fragmented datagram arrives first. + */ +static void test_fragment_add_seq_check_1(void) +{ + fragment_data *fd_head; + + printf("Starting test test_fragment_add_seq_check_1\n"); + + pinfo.fd->num = 1; + fd_head=fragment_add_seq_check(tvb, 10, &pinfo, 12, fragment_table, + reassembled_table, 1, 50, FALSE); + + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(0,g_hash_table_size(reassembled_table)); + ASSERT_EQ(NULL,fd_head); + + /* Now add the missing segment */ + pinfo.fd->num = 2; + fd_head=fragment_add_seq_check(tvb, 5, &pinfo, 12, fragment_table, + reassembled_table, 0, 60, TRUE); + + ASSERT_EQ(0,g_hash_table_size(fragment_table)); + ASSERT_EQ(2,g_hash_table_size(reassembled_table)); + ASSERT_NE(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(0,fd_head->frame); /* unused */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(110,fd_head->len); /* the length of data we have */ + ASSERT_EQ(1,fd_head->datalen); /* seqno of the last fragment we have */ + ASSERT_EQ(2,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET,fd_head->flags); + ASSERT_NE(NULL,fd_head->data); + ASSERT_NE(NULL,fd_head->next); + + ASSERT_EQ(2,fd_head->next->frame); + ASSERT_EQ(0,fd_head->next->offset); /* seqno */ + ASSERT_EQ(60,fd_head->next->len); /* segment length */ + ASSERT_EQ(0,fd_head->next->flags); + ASSERT_EQ(NULL,fd_head->next->data); + ASSERT_NE(NULL,fd_head->next->next); + + ASSERT_EQ(1,fd_head->next->next->frame); + ASSERT_EQ(1,fd_head->next->next->offset); /* seqno */ + ASSERT_EQ(50,fd_head->next->next->len); /* segment length */ + ASSERT_EQ(0,fd_head->next->next->flags); + ASSERT_EQ(NULL,fd_head->next->next->data); + ASSERT_EQ(NULL,fd_head->next->next->next); + + /* test the actual reassembly */ + ASSERT(!memcmp(fd_head->data,data+5,60)); + ASSERT(!memcmp(fd_head->data+60,data+10,50)); +} + +/********************************************************************************** + * + * fragment_add_seq_802_11 + * + *********************************************************************************/ + +/* Tests the 802.11 hack. + */ +static void test_fragment_add_seq_802_11_0(void) +{ + fragment_data *fd_head; + + printf("Starting test test_fragment_add_seq_802_11_0\n"); + + /* the 802.11 hack is that some non-fragmented datagrams have non-zero + * fragment_number; test for this. */ + + pinfo.fd->num = 1; + fd_head=fragment_add_seq_802_11(tvb, 10, &pinfo, 12, fragment_table, + reassembled_table, 10, 50, FALSE); + + ASSERT_EQ(0,g_hash_table_size(fragment_table)); + ASSERT_EQ(1,g_hash_table_size(reassembled_table)); + ASSERT_NE(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(0,fd_head->frame); /* unused */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* unused */ + ASSERT_EQ(0,fd_head->datalen); /* unused */ + ASSERT_EQ(1,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE,fd_head->flags); + ASSERT_EQ(NULL,fd_head->data); + ASSERT_EQ(NULL,fd_head->next); +} + +/* Reuse the fragment_add_seq_check testcases */ +static void test_fragment_add_seq_802_11_1(void) +{ + printf("Starting test test_fragment_add_seq_802_11_1\n"); + test_fragment_add_seq_check_work(fragment_add_seq_802_11); +} + +/********************************************************************************** + * + * fragment_add_seq_next + * + *********************************************************************************/ + +/* Simple test case for fragment_add_seq_next. + * Adds a couple of fragments (with one for a different datagram in between), + * and checks that they are reassembled correctly. + */ +static void test_simple_fragment_add_seq_next(void) +{ + fragment_data *fd_head; + + printf("Starting test test_simple_fragment_add_seq_next\n"); + + pinfo.fd->num = 1; + fd_head=fragment_add_seq_next(tvb, 10, &pinfo, 12, fragment_table, + reassembled_table, 50, TRUE); + + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(0,g_hash_table_size(reassembled_table)); + ASSERT_EQ(NULL,fd_head); + + /* adding the same fragment again should do nothing, even with different + * offset etc */ + pinfo.fd->flags.visited = 1; + fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 12, fragment_table, + reassembled_table, 60, TRUE); + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(0,g_hash_table_size(reassembled_table)); + ASSERT_EQ(NULL,fd_head); + + /* start another pdu (just to confuse things) */ + pinfo.fd->flags.visited = 0; + pinfo.fd->num = 2; + fd_head=fragment_add_seq_next(tvb, 15, &pinfo, 13, fragment_table, + reassembled_table, 60, TRUE); + ASSERT_EQ(2,g_hash_table_size(fragment_table)); + ASSERT_EQ(0,g_hash_table_size(reassembled_table)); + ASSERT_EQ(NULL,fd_head); + + + /* now we add the terminal fragment of the first datagram */ + pinfo.fd->num = 3; + fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 12, fragment_table, + reassembled_table, 60, FALSE); + + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(2,g_hash_table_size(reassembled_table)); + ASSERT_NE(NULL,fd_head); + + /* check the contents of the structure */ + ASSERT_EQ(0,fd_head->frame); /* unused */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(110,fd_head->len); /* the length of data we have */ + ASSERT_EQ(1,fd_head->datalen); /* seqno of the last fragment we have */ + ASSERT_EQ(3,fd_head->reassembled_in); + ASSERT_EQ(FD_DEFRAGMENTED|FD_BLOCKSEQUENCE|FD_DATALEN_SET,fd_head->flags); + ASSERT_NE(NULL,fd_head->data); + ASSERT_NE(NULL,fd_head->next); + + ASSERT_EQ(1,fd_head->next->frame); + ASSERT_EQ(0,fd_head->next->offset); /* seqno */ + ASSERT_EQ(50,fd_head->next->len); /* segment length */ + ASSERT_EQ(0,fd_head->next->flags); + ASSERT_EQ(NULL,fd_head->next->data); + ASSERT_NE(NULL,fd_head->next->next); + + ASSERT_EQ(3,fd_head->next->next->frame); + ASSERT_EQ(1,fd_head->next->next->offset); /* seqno */ + ASSERT_EQ(60,fd_head->next->next->len); /* segment length */ + ASSERT_EQ(0,fd_head->next->next->flags); + ASSERT_EQ(NULL,fd_head->next->next->data); + ASSERT_EQ(NULL,fd_head->next->next->next); + + /* test the actual reassembly */ + ASSERT(!memcmp(fd_head->data,data+10,50)); + ASSERT(!memcmp(fd_head->data+50,data+5,60)); +} + + +/* This tests the case where some data is missing from one of the fragments. + * It should prevent reassembly. + */ +static void test_missing_data_fragment_add_seq_next(void) +{ + fragment_data *fd_head; + + printf("Starting test test_missing_data_fragment_add_seq_next\n"); + + /* attempt to add a fragment which is longer than the data available */ + pinfo.fd->num = 1; + fd_head=fragment_add_seq_next(tvb, 10, &pinfo, 12, fragment_table, + reassembled_table, DATA_LEN-9, TRUE); + + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(0,g_hash_table_size(reassembled_table)); + ASSERT_NE(NULL,fd_head); + + /* check the contents of the structure. Reassembly failed so everything + * should be null (meaning, just use the original tvb) */ + ASSERT_EQ(0,fd_head->frame); /* unused */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* the length of data we have */ + ASSERT_EQ(0,fd_head->datalen); /* seqno of the last fragment we have */ + ASSERT_EQ(0,fd_head->reassembled_in); + ASSERT_EQ(FD_BLOCKSEQUENCE,fd_head->flags & 0x1ff); + ASSERT_EQ(NULL,fd_head->data); + ASSERT_EQ(NULL,fd_head->next); + + /* add another fragment (with all data present) */ + pinfo.fd->num = 4; + fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 12, fragment_table, + reassembled_table, 60, FALSE); + + /* XXX: it's not clear that this is the right result; however it's what the + * code does... + */ + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(0,g_hash_table_size(reassembled_table)); + ASSERT_EQ(NULL,fd_head); + + + /* check what happens when we revisit the packets */ + pinfo.fd->flags.visited = TRUE; + pinfo.fd->num = 1; + + fd_head=fragment_add_seq_next(tvb, 10, &pinfo, 12, fragment_table, + reassembled_table, DATA_LEN-9, TRUE); + + /* We just look in the reassembled_table for this packet. It never got put + * there, so this always returns null. + * + * That's crazy, because it means that the subdissector will see the data + * exactly once - on the first pass through the capture (well, assuming it + * doesn't bother to check fd_head->reassembled_in); however, that's + * what the code does... + */ + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(0,g_hash_table_size(reassembled_table)); + ASSERT_EQ(NULL,fd_head); + + pinfo.fd->num = 4; + fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 12, fragment_table, + reassembled_table, 60, FALSE); + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(0,g_hash_table_size(reassembled_table)); + ASSERT_EQ(NULL,fd_head); +} + + +/* + * we're going to do something similar now, but this time it is the second + * fragment which has something missing. + */ +static void test_missing_data_fragment_add_seq_next_2(void) +{ + fragment_data *fd_head; + + printf("Starting test test_missing_data_fragment_add_seq_next_2\n"); + + pinfo.fd->num = 11; + fd_head=fragment_add_seq_next(tvb, 10, &pinfo, 24, fragment_table, + reassembled_table, 50, TRUE); + + ASSERT_EQ(1,g_hash_table_size(fragment_table)); + ASSERT_EQ(0,g_hash_table_size(reassembled_table)); + ASSERT_EQ(NULL,fd_head); + + pinfo.fd->num = 12; + fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 24, fragment_table, + reassembled_table, DATA_LEN-4, FALSE); + + /* XXX: again, i'm really dubious about this. Surely this should return all + * the data we had, for a best-effort attempt at dissecting it? + * And it ought to go into the reassembled table? + */ + ASSERT_EQ(0,g_hash_table_size(fragment_table)); + ASSERT_EQ(0,g_hash_table_size(reassembled_table)); + ASSERT_EQ(NULL,fd_head); + + /* check what happens when we revisit the packets */ + pinfo.fd->flags.visited = TRUE; + pinfo.fd->num = 11; + + fd_head=fragment_add_seq_next(tvb, 10, &pinfo, 24, fragment_table, + reassembled_table, 50, TRUE); + + /* As before, this returns NULL because the fragment isn't in the + * reassembled_table. At least this is a bit more consistent than before. + */ + ASSERT_EQ(0,g_hash_table_size(fragment_table)); + ASSERT_EQ(0,g_hash_table_size(reassembled_table)); + ASSERT_EQ(NULL,fd_head); + + pinfo.fd->num = 12; + fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 24, fragment_table, + reassembled_table, DATA_LEN-4, FALSE); + ASSERT_EQ(0,g_hash_table_size(fragment_table)); + ASSERT_EQ(0,g_hash_table_size(reassembled_table)); + ASSERT_EQ(NULL,fd_head); + +} + +/* + * This time, our datagram only has one segment, but it has data missing. + */ +static void test_missing_data_fragment_add_seq_next_3(void) +{ + fragment_data *fd_head; + + printf("Starting test test_missing_data_fragment_add_seq_next_3\n"); + + pinfo.fd->num = 20; + fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 30, fragment_table, + reassembled_table, DATA_LEN-4, FALSE); + + ASSERT_EQ(0,g_hash_table_size(fragment_table)); + ASSERT_EQ(1,g_hash_table_size(reassembled_table)); + ASSERT_NE(NULL,fd_head); + + /* check the contents of the structure. */ + ASSERT_EQ(0,fd_head->frame); /* unused */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* the length of data we have */ + ASSERT_EQ(0,fd_head->datalen); /* seqno of the last fragment we have */ + ASSERT_EQ(20,fd_head->reassembled_in); + ASSERT_EQ(FD_BLOCKSEQUENCE|FD_DEFRAGMENTED,fd_head->flags); + ASSERT_EQ(NULL,fd_head->data); + ASSERT_EQ(NULL,fd_head->next); + + /* revisiting the packet ought to produce the same result. */ + pinfo.fd->flags.visited = TRUE; + + pinfo.fd->num = 20; + fd_head=fragment_add_seq_next(tvb, 5, &pinfo, 30, fragment_table, + reassembled_table, DATA_LEN-4, FALSE); + + ASSERT_EQ(0,g_hash_table_size(fragment_table)); + ASSERT_EQ(1,g_hash_table_size(reassembled_table)); + ASSERT_NE(NULL,fd_head); + ASSERT_EQ(0,fd_head->frame); /* unused */ + ASSERT_EQ(0,fd_head->offset); /* unused */ + ASSERT_EQ(0,fd_head->len); /* the length of data we have */ + ASSERT_EQ(0,fd_head->datalen); /* seqno of the last fragment we have */ + ASSERT_EQ(20,fd_head->reassembled_in); + ASSERT_EQ(FD_BLOCKSEQUENCE|FD_DEFRAGMENTED,fd_head->flags); + ASSERT_EQ(NULL,fd_head->data); + ASSERT_EQ(NULL,fd_head->next); +} + + +/********************************************************************************** + * + * main + * + *********************************************************************************/ + +int main(int argc, char **argv) +{ + frame_data fd; + char src[] = {1,2,3,4}, dst[] = {5,6,7,8}; + unsigned int i; + void (*tests[])(void) = { + test_simple_fragment_add_seq, + test_fragment_add_seq_partial_reassembly, + test_fragment_add_dcerpc_dg, + test_fragment_add_seq_check, + test_fragment_add_seq_check_1, + test_fragment_add_seq_802_11_0, + test_fragment_add_seq_802_11_1, + test_simple_fragment_add_seq_next, + test_missing_data_fragment_add_seq_next, + test_missing_data_fragment_add_seq_next_2, + test_missing_data_fragment_add_seq_next_3 + }; + + /* we don't use our params */ + argc=argc; argv=argv; + + /* initialise stuff */ + ep_init_chunk(); + tvbuff_init(); + reassemble_init(); + + /* a tvbuff for testing with */ + data = g_malloc(DATA_LEN); + /* make sure it's full of stuff */ + for(i=0; i<DATA_LEN; i++) { + data[i]=i & 0xFF; + } + tvb = tvb_new_real_data(data, DATA_LEN, DATA_LEN*2); + + /* other test stuff */ + pinfo.fd = &fd; + fd.flags.visited = 0; + SET_ADDRESS(&pinfo.src,AT_IPv4,4,src); + SET_ADDRESS(&pinfo.dst,AT_IPv4,4,dst); + + /*************************************************************************/ + for(i=0; i < sizeof(tests)/sizeof(tests[0]); i++ ) { + /* re-init the fragment tables */ + fragment_table_init(&fragment_table); + ASSERT(fragment_table != NULL); + + reassembled_table_init(&reassembled_table); + ASSERT(reassembled_table != NULL); + + pinfo.fd->flags.visited = FALSE; + + tests[i](); + } + + printf(failure?"FAILURE\n":"SUCCESS\n"); + return failure; +} |