AMOS-ss16-proj3 / amos-ss16-proj3

Repository for the wireshark plugin development project of the AMOS 16 course
GNU Affero General Public License v3.0
10 stars 12 forks source link

Data_Structure #4

Closed Naveezfau closed 8 years ago

Naveezfau commented 8 years ago

Data Structure

  1. Setting up your protocol dissector code amos-ss16-proj3/src/plugins/doip/ 1.1 Skeleton code This file also provides the information about traffic of DoiP protocols and working with header files. The start of code lives in the file "packet-PROTOABBREV.c" in the same source directory packet-DOIP.c is abbreviated name of dissector. Usually, you will put your newly created dissector file into the directory epan/dissectors/, just like all the other packet-*.c files already in there. Before define Dissector registration API to register with a lower level protocol (this is the vast majority) don't need to define a prototype in their .h file. Main dissector routine should have a prototype in a header file whose name is "packet-", followed by the abbreviated ".h"; dissector file that calls your dissector should be changed to include that file .Don’t include all the headers listed in the main code, you may need to include additional headers.

1.2 Explanation of needed substitutions in code skeleton In the skeleton sample code the following strings should be substituted with your information YOUR_NAME, YOUR_EMAIL_ADDRESS, PROTONAME, PROTOSHORTNAME PROTOABBREV, FIELDNAME, FIELDABBREV, FIELDTYPE, FT_OID FIELDDISPLAY, BASE_HEX_DEC, FIELDCONVERT, BITMASK, FIELDDESCR, PARENT_SUBFIELD, ID_VALUE. If, for example, PROTONAME is "diagnosis over internet protocol ", PROTOSHORTNAME would be "DOIP", and PROTOABBREV would be "doip". 1.3The doip dissector and the data it receives 1.3.1 Header file. in this data dissector not own self registration register itself with the lower level dissector, or if the protocol dissector wants/needs to expose code to other sub dissectors. The dissector must be declared exactly as follows in the file packet-doip.h int dissect_diop(tvbuff_t tvb, packet_info pinfo, proto_tree tree); 1.3.2 Extracting data from packets. The "tvb" argument to a dissector points to a buffer containing the raw data to be analyzed by the dissector; for example, for a protocol running a top UDP, it contains the UDP payload (but not the UDP header, or any protocol headers above it). A tvbuffer is an opaque data structure, the internal data structures are hidden and the data must be accessed via the tvbuffer accessors. By accessors for a maximum of 8-bits, 16-bits 32-bits asn so on others guint8 tvb_get_bits8(tvbuff_t tvb, gint bit_offset, const gint no_of_bits); guint16 tvb_get_bits16(tvbuff_t tvb, guint bit_offset, const gint no_of_bits, const guint encoding); Single-byte accessor guint8 tvb_get_guint8(tvbuff_t tvb, const gint offset); Network-to-host-order accessors for 16 bit and so on guint16 tvb_get_ntohs(tvbuff_t tvb, const gint offset); Network-to-host-order accessors for single-precision and double-precision IEEE floating-point numbers: gfloat tvb_get_ntohieee_float(tvbuff_t tvb, const gint offset); gdouble tvb_get_ntohieee_double(tvbuff_t tvb, const gint offset); Little-Endian-to-host-order accessors for 16-bit integers and so on guint16 tvb_get_letohs(tvbuff_t tvb, const gint offset); guint32 tvb_get_letoh24(tvbuff_t tvb, const gint offset) Accessors for IPv4 and IPv6 addresses: guint32 tvb_get_ipv4(tvbuff_t tvb, const gint offset); void tvb_get_ipv6(tvbuff_t tvb, const gint offset, struct e_in6_addr addr); NOTE: IPv4 addresses are not to be converted to host byte order before being passed to "proto_tree_add_ipv4() You should use "tvb_get_ipv4()" to fetch them, not "tvb_get_ntohl() Accessors for GUID: void tvb_get_ntohguid(tvbuff_t tvb, const gint offset, e_guid_t guid); String accessors: guint8 tvb_get_string(wmem_allocator_t scope, tvbuff_t tvb, const gint offset, const gint length); tvb_get_string() returns a buffer allocated by g_malloc() if scope is set to NULL (in that case memory must be explicitely freed), or with the allocator lifetime if scope is not NULL. The offset and returned length pointer are in bytes, not UTF-16 characters. Byte Array Accessors: gchar tvb_bytes_to_str(tvbuff_t *tvb, gint offset, gint len);

Formats a bunch of data from a tvbuff as bytes, returning a pointer to the string with the data formatted as two hex digits for each byte.The string pointed to is stored in an "ep_alloc'd" buffer which will be freed before the next frame is dissected. The formatted string will contain the hex digits for at most the first 16 bytes of the data. If len is greater than 16 bytes, a trailing "..." will be added to the string. gchar _tvb_bytes_to_str_punct(tvbuff_t tvb, gint offset, gint len, gchar punct); This function is similar to tvb_bytes_to_str(...) except that 'punct' is insertedbetween the hex representation of each byte. gchar tvb_bytes_to_str_punct(tvbuff_t tvb, gint offset, gint len, gchar punct); This function is similar to tvb_bytes_tostr(...) except that 'punct' is inserted between the hex representation of each byte. Copying memory: guint8 tvb_memcpy(tvbuff_t tvb, guint8 target, gint offset, gint length); Copies into the specified target the specified length's worth of data from the specified tvbuff, starting at the specified offset. guint8* tvb_memdup(wmem_allocator_t _scope, tvbuff_t tvb, gint offset, gint length); Returns a buffer, allocated with "gmalloc()" if scope is NULL, or with the specified pool. Pointer-retrieval: / WARNING! Don't use this function. There is almost always a better way.

1.4.2 The col_add_str function.

'col_add_str' takes a string as its third argument, and sets the value for the column to that value. It takes the same arguments as 'col_set_str', but copies the string, so that if the string is, forexample, an automatic variable that won't remain in scope when the dissector returns, it's safe to use. 1.4.3 The col_add_fstr function. 'col_add_fstr' takes a 'printf'-style format string as its third argument, and 'printf'-style arguments corresponding to '%' format items in that string as its subsequent arguments. For example, to set the "Info" field to " request, bytes", where "reqtype" is a string containing the type of the request in the packet and "n" is an unsigned integer containing the number of bytes in the request: col_add_fstr(pinfo->cinfo, COL_INFO, "%s request, %u bytes", reqtype, n); Don't use 'col_add_fstr' with a format argument of just "%s" - 'col_add_str', or possibly even 'col_set_str' if the string that matches the "%s" is a static constant string, will do the same job more efficiently. 1.4.4 The col_append_str function. Sometimes the value of a column, especially the "Info" column, can't be conveniently constructed at a single point in the dissection process; for example, it might contain small bits of information from many of the fields in the packet. 'col_append_str' takes, as arguments, the same arguments as 'col_add_str', but the string is appended to the end of the current value for the column, rather than replacing the value for that column. (Note that no blank separates the appended string from the string to which it is appended; if you want a blank there, you must add it yourself as part of the string being appended. 1.4.9 The col_set_time function. The 'col_set_time' function takes an nstime value as its third argument. This nstime value is a relative value and will be added as such to the column. The fourth argument is the filtername holding this value. This way, rightclicking on the column makes it possible to build a filter based on the time-value.For example: nstime_delta(&ts, &pinfo->fd->abs_ts, &tcpd->ts_first); col_set_time(pinfo->cinfo, COL_REL_CONV_TIME, &ts, "tcp.time_relative"); 1.5 Constructing the protocol tree The middle pane of the main window, and the top most pane of a packet popup window, is constructed from the "protocol tree" for a packet. The protocol tree, or proto_tree, is a GNode, the N-way tree structure available within GLIB. Of course the protocol dissectors don't care what a proto_tree really is; they just pass the proto_tree pointer as an argument to the routines which allow them to add items and new branches. When a packet is selected in the packet-list pane, or a packet popup window is created, a new logical protocol tree (proto_tree) is created. The pointer to the proto_tree (in this case, 'protocol tree'), is passed to the top-level protocol dissector, and then to all subsequent protocol dissectors for that packet, and then the GUI tree is drawn via proto_tree_draw().The logical proto_tree needs to know detailed information about the protocolsand fields about which information will be collected from the dissection routines. each protocol should have a register routine, which will be called when Wireshark starts. The code to call the register routines is generated automatically; to arrange that a protocol's register routine be called at startup: the file containing a dissector's "register" routine must be added to "DISSECTOR_SRC" in "epan/dissectors/Makefile.common" (and in "epan/CMakeLists.txt"); the "register" routine must have a name of the form "proto_register_doip"; the "register" routine must take no argument, and return no value; the "register" routine's name must appear in the source file either at the beginning of the line, or preceded only by "void " at the beginning of the line (that would typically be the definition) - other white space shouldn't cause a problem, e.g. void proto_register_XXX(void) { }and void proto_register_XXX( void ) { } and so on should work. Some dissectors will need to create branches within their tree to help organize header fields. These branches should be registered as header fields. Only true protocols should be registered as protocols. This is so that a display filter user interface knows how to distinguish protocols from fields. A protocol is registered with the name of the protocol and its abbreviation. int proto_frame;

    proto_frame = proto_register_protocol (
            /* Diagnostic over IP */            "Frame",
            /* DoiP */      "Frame",
            /* doip */          "frame" );

A header field is also registered with its name and abbreviation, but information about its data type is needed. It helps to look at the header_field_info struct to see what information is expected: struct header_field_info { const char * Diagnostic over IP; const char doip; enum ftenum type; int proto_doip = -1; const void strings; guint32 bitmask; const char *blurb; ..... }; The abbreviation is the identifier used in a display filter. If it is an empty string then the field will not be filterable. FT_NONE A field that represents a data structure with a subtree below it containing fields for the members of the structure, or that represents an array with a subtree below it containing fields for the members of the array, might be an FT_NONE field. FT_PROTOCOL Used for protocols which will be placing themselves as top-level items in the "Packet Details" pane of the UI. FT_BOOLEAN
0 means "false", any other value means "true". FT_FRAMENUM A frame number; if this is used, the "Go To Corresponding Frame" menu item can work on that field. FT_UINT8
An 8-bit unsigned integer. FT_UINT16
A 16-bit unsigned integer. and so other data types FT_STRING
A string of characters, not necessarily NULL-terminated, but possibly NULL-padded This, and the other string-of-characters types, are to be used for text strings, not raw binary data. FT_UINT_STRING
A counted string of characters, consisting of a count (represented as an integral value, of width given in the proto_tree_add_item() call) followed immediately by that number of characters. FT_ETHER A six octet string displayed in Ethernet-address format. FT_BYTES A string of bytes with arbitrary values; used for raw binary data. FT_UINT_BYTES A counted string of bytes, consisting of a count (represented as an integral value, of width given in the proto_tree_add_item() call) followed immediately by that number of arbitrary values; used for raw binary data. FT_IPv4 A version 4 IP address (4 bytes) displayed in dotted-quad IP address format (4 decimal numbers separated by dots). FT_IPv6 A version 6 IP address (16 bytes) displayed in standard IPv6 address format. FT_IPXNET
An IPX address displayed in hex as a 6-byte network number followed by a 6-byte station address. FT_GUID
A Globally Unique Identifier FT_OID
An ASN.1 Object Identifier FT_EUI64
A EUI-64 Address

Some of these field types are still not handled in the display filter routines, but the most common ones are. The FT_UINT* variables all represent unsigned integers, and the FT_INT* variables all represent signed integers; the number on the end represent how many bits are used to represent the number. Strings value_string Some integer fields, of type FT_UINT*, need labels to represent the true value of a field. You could think of those fields as having an enumerated data type, rather than an integral data type. A 'value_string' structure is a way to map values to strings.

typedef struct _value_string {
    guint32  value;
    gchar   *strptr;
} value_string;

For fields of that type, you would declare an array of "value_string"s: static const value_string valstringname[] = { { INTVAL1, "Descriptive String 1" }, { INTVAL2, "Descriptive String 2" }, { 0, NULL } }; Ranges If the field has a numeric type that might logically fit in ranges of values one can use a range_string struct. Thus a 'range_string' structure is a way to map ranges to strings. typedef struct _range_string { guint32 value_min; guint32 value_max; const gchar *strptr; } range_string; For fields of that type, you would declare an array of "range_string"s:

static const range_string rvalstringname[] = {
    { INTVAL_MIN1, INTVALMAX1, "Descriptive String 1" },
    { INTVAL_MIN2, INTVALMAX2, "Descriptive String 2" },
    { 0,           0,          NULL                   }
};

Booleans FT_BOOLEANs have a default map of 0 = "False", 1 (or anything else) = "True". Sometimes it is useful to change the labels for boolean values (e.g., to "Yes"/"No", "Fast"/"Slow", etc.). For these mappings, a struct called true_false_string is used.

typedef struct true_false_string {
    char    *true_string;
    char    *false_string;
} true_false_string;

For Boolean fields for which "False" and "True" aren't the desired labels, you would declare a "true_false_string"s:

static const true_false_string boolstringname = {
    "String for True",
    "String for False"};

'strings' field would be set to NULL. 1.5.1 Field Registration. Protocol registration is handled by creating an instance of the header_field_info struct (or an array of such structs), and calling the registration function along with the registration ID of the protocol that is the parent of the fields. Here is a complete example:

static int proto_eg = -1;
static int hf_field_a = -1;
static int hf_field_b = -1;

static hf_register_info hf[] = { { &hf_field_a, { "Field A", "proto.field_a", FT_UINT8, BASE_HEX, NULL, 0xf0, "Field A represents Apples", HFILL }}, { &hf_field_b, { "Field B", "proto.field_b", FT_UINT16, BASE_DEC, VALS(vs), 0x0, "Field B represents Bananas", HFILL }} };