From fb0c288f99518eac830cf29e92c3543a8045878e Mon Sep 17 00:00:00 2001 From: Paul Offord Date: Mon, 3 Oct 2016 09:09:18 +0100 Subject: [PATCH] transum: plugin code A plugin to calculate response, service and spread time values based on the RTE model. Bug: 12892 Change-Id: I47d7e5354fc269916851a318fef10b826897eaf8 Reviewed-on: https://code.wireshark.org/review/17750 Petri-Dish: Anders Broman Petri-Dish: Alexis La Goutte Petri-Dish: Michael Mann Tested-by: Petri Dish Buildbot Reviewed-by: Michael Mann Reviewed-by: Anders Broman --- plugins/transum/AUTHORS | 2 + plugins/transum/COPYING | 340 ++++++++ plugins/transum/NEWS | 2 + plugins/transum/README | 6 + plugins/transum/decoders.c | 303 +++++++ plugins/transum/decoders.h | 31 + plugins/transum/extractors.c | 120 +++ plugins/transum/extractors.h | 33 + plugins/transum/moduleinfo.h | 39 + plugins/transum/packet-transum.c | 1408 ++++++++++++++++++++++++++++++ plugins/transum/packet-transum.h | 185 ++++ plugins/transum/preferences.h | 55 ++ 12 files changed, 2524 insertions(+) create mode 100644 plugins/transum/AUTHORS create mode 100644 plugins/transum/COPYING create mode 100644 plugins/transum/NEWS create mode 100644 plugins/transum/README create mode 100644 plugins/transum/decoders.c create mode 100644 plugins/transum/decoders.h create mode 100644 plugins/transum/extractors.c create mode 100644 plugins/transum/extractors.h create mode 100644 plugins/transum/moduleinfo.h create mode 100644 plugins/transum/packet-transum.c create mode 100644 plugins/transum/packet-transum.h create mode 100644 plugins/transum/preferences.h diff --git a/plugins/transum/AUTHORS b/plugins/transum/AUTHORS new file mode 100644 index 0000000000..109c3fcdaa --- /dev/null +++ b/plugins/transum/AUTHORS @@ -0,0 +1,2 @@ +Author : +Paul Offord diff --git a/plugins/transum/COPYING b/plugins/transum/COPYING new file mode 100644 index 0000000000..f7962229f1 --- /dev/null +++ b/plugins/transum/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/plugins/transum/NEWS b/plugins/transum/NEWS new file mode 100644 index 0000000000..2cda5d8a9b --- /dev/null +++ b/plugins/transum/NEWS @@ -0,0 +1,2 @@ +August 5, 2016 2.0.1 - Initial version +September 30,2016 2.0.2 - Bug fix revision \ No newline at end of file diff --git a/plugins/transum/README b/plugins/transum/README new file mode 100644 index 0000000000..af6b86e93b --- /dev/null +++ b/plugins/transum/README @@ -0,0 +1,6 @@ +Advance7 has released under GPL this plugin +for Wireshark. It produces detailed response +time information based on the RTE model. + +Advance7 can be found at http://www.advance7.com/ +The author is Paul Offord diff --git a/plugins/transum/decoders.c b/plugins/transum/decoders.c new file mode 100644 index 0000000000..347f5af02c --- /dev/null +++ b/plugins/transum/decoders.c @@ -0,0 +1,303 @@ +/* decoders.c +* Routines for the TRANSUM response time analyzer post-dissector +* By Paul Offord +* Copyright 2016 Advance Seven Limited +* +* Wireshark - Network traffic analyzer +* By Gerald Combs +* Copyright 1998 Gerald Combs +* +* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "config.h" + +#include +#include +#include +#include +#include "packet-transum.h" +#include "preferences.h" +#include "extractors.h" + +extern void add_detected_tcp_svc(guint16 port); +extern TSUM_PREFERENCES preferences; +extern PKT_INFO *sub_packet; +extern gboolean *dcerpc_req_pkt_type; +extern gboolean *dcerpc_context_zero; +extern HF_OF_INTEREST hf_of_interest; + + +/* Returns the number of sub-packets of interest */ +int decode_syn(packet_info *pinfo, proto_tree *tree) +{ + if (sub_packet[0].tcp_flags_ack) + sub_packet[0].rrpd.c2s = FALSE; + else + { + sub_packet[0].rrpd.c2s = TRUE; + sub_packet[0].rrpd.state = RRPD_STATE_4; + add_detected_tcp_svc(sub_packet[0].dstport); + } + + sub_packet[0].rrpd.session_id = 1; + sub_packet[0].rrpd.msg_id = 1; + sub_packet[0].rrpd.suffix = 1; + sub_packet[0].rrpd.decode_based = TRUE; + sub_packet[0].rrpd.calculation = RTE_CALC_SYN; + sub_packet[0].pkt_of_interest = TRUE; + + return 1; +} + +/* + This function sets basic information in the sub_packet entry. + Because we don't expect multiple DCE-RPC messages in a single packet + we only use sub_packet[0]. + + Returns the number of sub-packets of interest, which in this case is always 1. + */ +int decode_dcerpc(packet_info *pinfo, proto_tree *tree) +{ + guint32 field_uint[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */ + size_t field_value_count; /* How many entries are there in the extracted field array */ + guint32 dcerpc_cn_ctx_id; + + if (!extract_uint(tree, hf_of_interest.dcerpc_ver, field_uint, &field_value_count)) + { + if (field_value_count) + sub_packet[0].dcerpc_ver = field_uint[0]; + } + + if (!extract_uint(tree, hf_of_interest.dcerpc_pkt_type, field_uint, &field_value_count)) + { + if (field_value_count) + sub_packet[0].dcerpc_pkt_type = field_uint[0]; + } + + if (field_value_count) + { + if (!extract_uint(tree, hf_of_interest.dcerpc_cn_ctx_id, field_uint, &field_value_count)) + { + if (field_value_count) + dcerpc_cn_ctx_id = field_uint[0]; + } + + if (dcerpc_context_zero[sub_packet[0].dcerpc_pkt_type]) + { /* This is needed to overcome an apparent Wireshark bug + found in the LUA code - is this still true in C? */ + sub_packet[0].rrpd.session_id = 1; + } + else + { + if (dcerpc_cn_ctx_id) + sub_packet[0].rrpd.session_id = dcerpc_cn_ctx_id; + else + sub_packet[0].rrpd.session_id = 1; + } + if (!extract_uint(tree, hf_of_interest.dcerpc_cn_call_id, field_uint, &field_value_count)) + { + if (field_value_count) + sub_packet[0].rrpd.msg_id = field_uint[0]; + } + } + else + { + /* + we don't have header information and so by setting the session_id and msg_id to zero + the rrpd functions will either create a new rrpd_list (or temp_rsp_rrpd_list) entry + or update the last entry for this ip_proto:stream_no. + */ + sub_packet[0].rrpd.session_id = 0; + sub_packet[0].rrpd.msg_id = 0; + } + + + if (dcerpc_req_pkt_type[sub_packet[0].dcerpc_pkt_type]) + { + sub_packet[0].rrpd.c2s = TRUE; + preferences.tcp_svc_port[sub_packet[0].dstport] = RTE_CALC_DCERPC; /* make sure we have this DCE-RPC service port set */ + } + else + { + sub_packet[0].rrpd.c2s = FALSE; + preferences.tcp_svc_port[sub_packet[0].srcport] = RTE_CALC_DCERPC; /* make sure we have this DCE-RPC service port set */ + } + + sub_packet[0].rrpd.suffix = 1; + sub_packet[0].rrpd.decode_based = TRUE; + sub_packet[0].rrpd.calculation = RTE_CALC_DCERPC; + sub_packet[0].pkt_of_interest = TRUE; + + return 1; +} + +/* Returns the number of sub-packets of interest */ +int decode_smb(packet_info *pinfo, proto_tree *tree) +{ + guint32 field_uint[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */ + size_t field_value_count; /* How many entries are there in the extracted field array */ + + guint64 ses_id[MAX_RETURNED_ELEMENTS]; + size_t ses_id_count; + guint64 msg_id[MAX_RETURNED_ELEMENTS]; + size_t msg_id_count; + + /* set the direction information */ + if (sub_packet[0].dstport == 445) + sub_packet[0].rrpd.c2s = TRUE; + else + sub_packet[0].rrpd.c2s = FALSE; + + extract_uint(tree, hf_of_interest.smb_mid, field_uint, &field_value_count); + + if (field_value_count) + { + sub_packet[0].rrpd.calculation = RTE_CALC_SMB1; + sub_packet[0].pkt_of_interest = FALSE; /* can't process SMB1 at the moment */ + return 0; + } + else + { + /* Default in case we don't have header information */ + sub_packet[0].rrpd.session_id = 0; + sub_packet[0].rrpd.msg_id = 0; + sub_packet[0].rrpd.suffix = 1; + sub_packet[0].rrpd.decode_based = TRUE; + sub_packet[0].rrpd.calculation = RTE_CALC_SMB2; + sub_packet[0].pkt_of_interest = TRUE; + + extract_si64(tree, hf_of_interest.smb2_msg_id, msg_id, &msg_id_count); + if (msg_id_count) /* test for header information */ + { + extract_ui64(tree, hf_of_interest.smb2_ses_id, ses_id, &ses_id_count); + + for (int i = 0; i < msg_id_count; i++) + { + sub_packet[i].rrpd.c2s = sub_packet[0].rrpd.c2s; + sub_packet[i].rrpd.ip_proto = sub_packet[0].rrpd.ip_proto; + sub_packet[i].rrpd.stream_no = sub_packet[0].rrpd.stream_no; + + sub_packet[i].rrpd.session_id = ses_id[i]; + sub_packet[i].rrpd.msg_id = msg_id[i]; + sub_packet[i].rrpd.suffix = 1; + + sub_packet[i].rrpd.decode_based = TRUE; + sub_packet[i].rrpd.calculation = RTE_CALC_SMB2; + sub_packet[i].pkt_of_interest = TRUE; + } + return (int)msg_id_count; + } + } + + return 1; +} + +/* Returns the number of sub-packets of interest */ +int decode_gtcp(packet_info *pinfo, proto_tree *tree) +{ + guint32 field_uint[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */ + gboolean field_bool[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */ + size_t field_value_count; /* How many entries are there in the extracted field array */ + + if (!extract_uint(tree, hf_of_interest.tcp_stream, field_uint, &field_value_count)) + sub_packet[0].rrpd.stream_no = field_uint[0]; + + sub_packet[0].srcport = pinfo->srcport; + sub_packet[0].dstport = pinfo->destport; + + if (!extract_uint(tree, hf_of_interest.tcp_len, field_uint, &field_value_count)) + sub_packet[0].len = field_uint[0]; + + if (!extract_bool(tree, hf_of_interest.tcp_flags_syn, field_bool, &field_value_count)) + sub_packet[0].tcp_flags_syn = field_bool[0]; + + if (!extract_bool(tree, hf_of_interest.tcp_flags_ack, field_bool, &field_value_count)) + sub_packet[0].tcp_flags_ack = field_bool[0]; + + if (!extract_bool(tree, hf_of_interest.tcp_flags_reset, field_bool, &field_value_count)) + sub_packet[0].tcp_flags_reset = field_bool[0]; + + if (!extract_bool(tree, hf_of_interest.tcp_retran, field_bool, &field_value_count)) + sub_packet[0].tcp_retran = field_bool[0]; + + if (!extract_bool(tree, hf_of_interest.tcp_keep_alive, field_bool, &field_value_count)) + sub_packet[0].tcp_keep_alive = field_bool[0]; + + if ((preferences.tcp_svc_port[sub_packet[0].dstport] || preferences.tcp_svc_port[sub_packet[0].srcport]) && (sub_packet[0].len > 0)) + { + if (preferences.tcp_svc_port[sub_packet[0].dstport]) + sub_packet[0].rrpd.c2s = TRUE; + + sub_packet[0].rrpd.session_id = 1; + sub_packet[0].rrpd.msg_id = 1; + sub_packet[0].rrpd.calculation = RTE_CALC_GTCP; + sub_packet[0].rrpd.decode_based = FALSE; + sub_packet[0].pkt_of_interest = TRUE; + + return 1; + } + + return 0; +} + +/* Returns the number of sub-packets of interest */ +int decode_dns(packet_info *pinfo, proto_tree *tree) +{ + guint32 field_uint[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */ + size_t field_value_count; /* How many entries are there in the extracted field array */ + + if (!extract_uint(tree, hf_of_interest.dns_id, field_uint, &field_value_count)) + sub_packet[0].rrpd.msg_id = field_uint[0]; + + sub_packet[0].rrpd.session_id = 1; + sub_packet[0].rrpd.suffix = 1; /* need to do something tricky here as dns.id gets reused */ + sub_packet[0].rrpd.decode_based = TRUE; + sub_packet[0].rrpd.calculation = RTE_CALC_DNS; + sub_packet[0].pkt_of_interest = TRUE; + + return 1; +} + +/* Returns the number of sub-packets of interest */ +int decode_gudp(packet_info *pinfo, proto_tree *tree) +{ + guint32 field_uint[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */ + size_t field_value_count; /* How many entries are there in the extracted field array */ + + sub_packet[0].srcport = pinfo->srcport; + sub_packet[0].dstport = pinfo->destport; + + if (!extract_uint(tree, hf_of_interest.udp_stream, field_uint, &field_value_count)) + sub_packet[0].rrpd.stream_no = field_uint[0]; + + if (!extract_uint(tree, hf_of_interest.udp_length, field_uint, &field_value_count)) + sub_packet[0].len = field_uint[0]; + + if (preferences.udp_svc_port[sub_packet[0].dstport] || preferences.udp_svc_port[sub_packet[0].srcport]) + { + if (preferences.udp_svc_port[sub_packet[0].dstport]) + sub_packet[0].rrpd.c2s = TRUE; + + sub_packet[0].rrpd.session_id = 1; + sub_packet[0].rrpd.msg_id = 1; + sub_packet[0].rrpd.suffix = 1; + sub_packet[0].rrpd.decode_based = FALSE; + sub_packet[0].rrpd.calculation = RTE_CALC_GUDP; + sub_packet[0].pkt_of_interest = TRUE; + } + + return 1; +} diff --git a/plugins/transum/decoders.h b/plugins/transum/decoders.h new file mode 100644 index 0000000000..18bdb07121 --- /dev/null +++ b/plugins/transum/decoders.h @@ -0,0 +1,31 @@ +/* decoders.h +* Header file for the TRANSUM response time analyzer post-dissector +* By Paul Offord +* Copyright 2016 Advance Seven Limited +* +* Wireshark - Network traffic analyzer +* By Gerald Combs +* Copyright 1998 Gerald Combs +* +* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "config.h" + +gboolean decode_syn(packet_info *pinfo, proto_tree *tree); +gboolean decode_dcerpc(packet_info *pinfo, proto_tree *tree); +gboolean decode_smb(packet_info *pinfo, proto_tree *tree); +gboolean decode_gtcp(packet_info *pinfo, proto_tree *tree); +gboolean decode_dns(packet_info *pinfo, proto_tree *tree); +gboolean decode_gudp(packet_info *pinfo, proto_tree *tree); diff --git a/plugins/transum/extractors.c b/plugins/transum/extractors.c new file mode 100644 index 0000000000..f2c72371cc --- /dev/null +++ b/plugins/transum/extractors.c @@ -0,0 +1,120 @@ +/* extractors.c +* Routines for the TRANSUM response time analyzer post-dissector +* By Paul Offord +* Copyright 2016 Advance Seven Limited +* +* Wireshark - Network traffic analyzer +* By Gerald Combs +* Copyright 1998 Gerald Combs +* +* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "config.h" +#include +#include +#include "extractors.h" + +/* + This function extracts a field value (e.g. tcp.len) from a tree. Because a packet may contain + multiple values for the the field the extracted values are returned in a result_array. The + number of array entries is returned in element_count. + + Return is 0 if all went well. If this function return -1 it is probably because the tree did not + include the field defined by the field_id. + */ +int extract_uint(proto_tree *tree, int field_id, guint32 *result_array, size_t *element_count) +{ + GPtrArray *finfo_array = proto_find_finfo(tree, field_id); + + if (finfo_array == NULL) { + return -1; + } + + *element_count = g_ptr_array_len(finfo_array); + + for (int i = 0; i < *element_count && i < MAX_RETURNED_ELEMENTS; i++) + { + result_array[i] = fvalue_get_uinteger(&((field_info*)finfo_array->pdata[i])->value); + } + + g_ptr_array_free(finfo_array, TRUE); + + return 0; +} + +int extract_ui64(proto_tree *tree, int field_id, guint64 *result_array, size_t *element_count) +{ + GPtrArray *finfo_array = proto_find_finfo(tree, field_id); + + if (finfo_array == NULL) { + return -1; + } + + *element_count = g_ptr_array_len(finfo_array); + + for (int i = 0; i < *element_count && i < MAX_RETURNED_ELEMENTS; i++) + { + result_array[i] = fvalue_get_uinteger64(&((field_info*)finfo_array->pdata[i])->value); + } + + g_ptr_array_free(finfo_array, TRUE); + + return 0; +} + +int extract_si64(proto_tree *tree, int field_id, guint64 *result_array, size_t *element_count) +{ + GPtrArray *finfo_array = proto_find_finfo(tree, field_id); + + if (finfo_array == NULL) { + return -1; + } + + *element_count = g_ptr_array_len(finfo_array); + + for (int i = 0; i < *element_count && i < MAX_RETURNED_ELEMENTS; i++) + { + result_array[i] = fvalue_get_sinteger64(&((field_info*)finfo_array->pdata[i])->value); + } + + g_ptr_array_free(finfo_array, TRUE); + + return 0; +} + +int extract_bool(proto_tree *tree, int field_id, gboolean *result_array, size_t *element_count) +{ + GPtrArray *finfo_array = proto_find_finfo(tree, field_id); + + if (finfo_array == NULL) { + return -1; + } + + *element_count = g_ptr_array_len(finfo_array); + + for (int i = 0; i < *element_count && i < MAX_RETURNED_ELEMENTS; i++) + { + fvalue_t *fv = &(((field_info*)finfo_array->pdata[i])->value); + + if (fv->value.uinteger) + result_array[i] = TRUE; + else + result_array[i] = FALSE; + } + + g_ptr_array_free(finfo_array, TRUE); + + return 0; +} diff --git a/plugins/transum/extractors.h b/plugins/transum/extractors.h new file mode 100644 index 0000000000..c1c0ff3b83 --- /dev/null +++ b/plugins/transum/extractors.h @@ -0,0 +1,33 @@ +/* extractors.h +* Header file for the TRANSUM response time analyzer post-dissector +* By Paul Offord +* Copyright 2016 Advance Seven Limited +* +* Wireshark - Network traffic analyzer +* By Gerald Combs +* Copyright 1998 Gerald Combs +* +* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "config.h" +#include +#include + +#define MAX_RETURNED_ELEMENTS 16 + +int extract_uint(proto_tree *tree, int field_id, guint32 *result_array, size_t *element_count); +int extract_ui64(proto_tree *tree, int field_id, guint64 *result_array, size_t *element_count); +int extract_si64(proto_tree *tree, int field_id, guint64 *result_array, size_t *element_count); +int extract_bool(proto_tree *tree, int field_id, gboolean *result_array, size_t *element_count); diff --git a/plugins/transum/moduleinfo.h b/plugins/transum/moduleinfo.h new file mode 100644 index 0000000000..0050ecad1d --- /dev/null +++ b/plugins/transum/moduleinfo.h @@ -0,0 +1,39 @@ +/* moduleinfo.h + * + * Module info header for wireshark plugins. + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* Included *after* config.h, in order to re-define these macros */ + +#ifdef PACKAGE +#undef PACKAGE +#endif + +/* Name of package */ +#define PACKAGE "transum" + + +#ifdef VERSION +#undef VERSION +#endif + +/* Version number of package */ +#define VERSION "2.0.2" diff --git a/plugins/transum/packet-transum.c b/plugins/transum/packet-transum.c new file mode 100644 index 0000000000..6b112702b4 --- /dev/null +++ b/plugins/transum/packet-transum.c @@ -0,0 +1,1408 @@ +/* packet-transum.c +* Routines for the TRANSUM response time analyzer post-dissector +* By Paul Offord +* Copyright 2016 Advance Seven Limited +* +* Wireshark - Network traffic analyzer +* By Gerald Combs +* Copyright 1998 Gerald Combs +* +* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +/* ToDo: Test handling of multiple SMB2 messages within a packet */ +/* ToDo: Rework the Summarizer code (future release) */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include "packet-transum.h" +#include "preferences.h" +#include "extractors.h" +#include "decoders.h" + +void proto_reg_handoff_transum(void); + + +#define CAPTURE_CLIENT 0 +#define CAPTURE_INTERMEDIATE 1 +#define CAPTURE_SERVICE 2 + +#define RTE_TIME_SEC 1 +#define RTE_TIME_MSEC 1000 +#define RTE_TIME_USEC 1000000 + +#define CONTINUE_PROCESSING TRUE + +#define RRPD_REQUIRES_SUFFIX TRUE +#define RRPD_NEEDS_NO_SUFFIX FALSE; + +#define SMB2_CMD_SESSION_SETUP 1 + +#define SIZEOF_TEMP_STRING 512 +#define SIZEOF_SUMMARY 1024 + +/* The following are the field ids for the protocol values used by TRANSUM */ +HF_OF_INTEREST hf_of_interest; + +range_t *tcp_svc_port_range_values; + +range_t *udp_svc_port_range_values; + +TSUM_PREFERENCES preferences; + + +gboolean *detected_tcp_svc = NULL; /* this array is used to track services detected during the syn/syn-ack process */ + +PKT_INFO *sub_packet = NULL; + +gboolean *dcerpc_req_pkt_type = NULL; /* used to indicate if a DCE-RPC pkt_type is a request */ + +/* +This array contains calls and returns that have no TRUE context_id +This is needed to overcome an apparent bug in Wireshark where +the field name of context id in parameters is the same as context id +in a message header +*/ +gboolean *dcerpc_context_zero= NULL; + +/* rrpd-related globals */ + +guint32 rrpd_suffix = 0; +guint32 dummy_msgid = 0xa7; /* This value is used for protocols that don't have msg_id such as GTCP, GUDP and SYN */ + +/* + The rrpd_list is the master array that holds information about all of the APDU Request-Response Pairs seen in the + trace. Each time an entry is added to this list the next_free_rrpd index is incremented. This index is used to + accelerate appending entries to the rrpd_list and also as the start point for find operations as these start from the + end of the list and search backwards through the list. + */ +RRPD *rrpd_list; +int next_free_rrpd = 0; + +/* + output_rrpd is an array of pointers to RRPDs on the rrpd_list. The index into the array is frame number. This array is + used during Wireshark's second scan. As each packet is processed, TRANSUM uses the packet's frame number to index into + this array to determine if we have RTE data for this particular packet, and if so the write_rte function is called. + */ +RRPD *output_rrpd[MAX_PACKETS]; + +/* + The temp_rsp_rrpd_list holds RRPDs for APDUs where we have not yet seen the header information and so we can't + fully qualify the identification of the RRPD (the identification being ip_proto:stream_no:session_id:msg_id:suffix). + This only occurs when a) we are using one of the decode_based calculations (such as SMB2), and b) when we have + TCP Reassembly enabled. Once we receive a header packet for an APDU we migrate the entry from this array to the + main rrpd_list. + */ +RRPD *temp_rsp_rrpd_list; /* Reuse these for speed and efficient memory use - issue a warning if we run out */ + + +static gint ett_transum = -1; +static gint ett_transum_header = -1; +static gint ett_transum_data = -1; + +int proto_transum = -1; + +int hf_tsum = -1; +int hf_tsum_status = -1; +int hf_tsum_time_units = -1; +int hf_tsum_req_first_seg = -1; +int hf_tsum_req_last_seg = -1; +int hf_tsum_rsp_first_seg = -1; +int hf_tsum_rsp_last_seg = -1; +int hf_tsum_apdu_rsp_time = -1; +int hf_tsum_service_time = -1; +int hf_tsum_req_spread = -1; +int hf_tsum_rsp_spread = -1; +int hf_tsum_clip_filter = -1; +int hf_tsum_calculation = -1; +int hf_tsum_summary = -1; + +static const enum_val_t capture_position_vals[] = { + { "TRACE_CAP_CLIENT", "Client", TRACE_CAP_CLIENT }, + { "TRACE_CAP_INTERMEDIATE", "Intermediate", TRACE_CAP_INTERMEDIATE }, + { "TRACE_CAP_SERVICE", "Service", TRACE_CAP_SERVICE }, + { NULL, NULL, 0} +}; + +static const enum_val_t time_multiplier_vals[] = { + { "RTE_TIME_SEC", "seconds", RTE_TIME_SEC }, + { "RTE_TIME_MSEC", "milliseconds", RTE_TIME_MSEC }, + { "RTE_TIME_USEC", "microseconds", RTE_TIME_USEC }, + { NULL, NULL, 0} +}; + +static int fake_tap = 0xa7a7a7a7; + + +void init_detected_tcp_svc() +{ + for (int i = 0; i < 64 * 1024; i++) + detected_tcp_svc[i] = FALSE; +} + +void add_detected_tcp_svc(guint16 port) +{ + detected_tcp_svc[port] = TRUE; +} + + +void init_dcerpc_data() +{ + for (int i = 0; i < 256; i++) + dcerpc_req_pkt_type[i] = FALSE; + + dcerpc_req_pkt_type[0] = TRUE; + dcerpc_req_pkt_type[11] = TRUE; + dcerpc_req_pkt_type[14] = TRUE; + + for (int i = 0; i < 256; i++) + dcerpc_context_zero[i] = FALSE; + + dcerpc_context_zero[11] = TRUE; + dcerpc_context_zero[12] = TRUE; + dcerpc_context_zero[14] = TRUE; + dcerpc_context_zero[15] = TRUE; + + return; +} + +void clear_rrpd(RRPD *rrpd) +{ + memset(rrpd, 0x00, sizeof(RRPD)); +} + +void init_rrpd_data() +{ + for (int i = 0; i < MAX_PACKETS; i++) + output_rrpd[i] = NULL; + + return; +} + +/* This function should be called before any change to RTE data. */ +void null_output_rrpd_entries(RRPD *in_rrpd) +{ + output_rrpd[in_rrpd->req_first_frame] = NULL; + output_rrpd[in_rrpd->req_last_frame] = NULL; + output_rrpd[in_rrpd->rsp_first_frame] = NULL; + output_rrpd[in_rrpd->rsp_last_frame] = NULL; +} + +/* This function should be called after any change to RTE data. */ +void update_output_rrpd(RRPD *in_rrpd) +{ + if (preferences.rte_on_first_req) + output_rrpd[in_rrpd->req_first_frame] = in_rrpd; + + if (preferences.rte_on_last_req) + output_rrpd[in_rrpd->req_last_frame] = in_rrpd; + + if (preferences.rte_on_first_rsp) + output_rrpd[in_rrpd->rsp_first_frame] = in_rrpd; + + if (preferences.rte_on_last_rsp) + output_rrpd[in_rrpd->rsp_last_frame] = in_rrpd; +} + +/* Return the index of the RRPD that has been appended */ +int append_to_rrpd_list(RRPD *in_rrpd) +{ + if (next_free_rrpd > MAX_RRPDS) + next_free_rrpd = 0; + + memcpy(&(rrpd_list[next_free_rrpd]), in_rrpd, sizeof(RRPD)); + + if (preferences.reassembly) + { + if (rrpd_list[next_free_rrpd].msg_id) + rrpd_list[next_free_rrpd].state = RRPD_STATE_3; + else + rrpd_list[next_free_rrpd].state = RRPD_STATE_1; + } + else + { + if (rrpd_list[next_free_rrpd].msg_id) + rrpd_list[next_free_rrpd].state = RRPD_STATE_4; + else + rrpd_list[next_free_rrpd].state = RRPD_STATE_2; + } + + update_output_rrpd(&rrpd_list[next_free_rrpd]); + + next_free_rrpd++; + + return (next_free_rrpd - 1); +} + +/* +This function finds the latest entry in the rrpd_list that matches the +ip_proto and stream_no values. If is_struct os true it will only match +if the session_id, msg_id and suffix are all zero or all ones. + +/* +This function finds the latest entry in the rrpd_list that matches the +ip_proto, stream_no, session_id, msg_id and suffix values. + +An input state value of 0 means that we don't care about state. + +Returns the rrpd_list index value of the match or -1 if no match is found. +*/ +int find_latest_rrpd(RRPD *in_rrpd, int state) +{ + int i; + int rrpd_index = -1; + + for (i = next_free_rrpd; i >= 0; i--) + { + if (rrpd_list[i].ip_proto == in_rrpd->ip_proto && rrpd_list[i].stream_no == in_rrpd->stream_no) + { + if (in_rrpd->decode_based) + { + /* If this is decode-based and we are checking for entries in RRPD_STATE_1 we need to match on ip_proto and stream_no alone. */ + if (state == RRPD_STATE_1) + { + if (rrpd_list[i].session_id == 0 && rrpd_list[i].msg_id == 0 && rrpd_list[i].suffix == 1) + { + rrpd_index = i; + break; + } + } + + /* if this stream is decode_based we need to take into account the session_id, msg_id and suffix */ + if (rrpd_list[i].session_id == in_rrpd->session_id && rrpd_list[i].msg_id == in_rrpd->msg_id && rrpd_list[i].suffix == in_rrpd->suffix) + { + if (state == RRPD_STATE_DONT_CARE || rrpd_list[i].state == state) + { + rrpd_index = i; + break; + } + } + } + else + { + /* if this stream is not decode_based we don't need to take into account the session_id, msg_id and suffix */ + if (state == RRPD_STATE_DONT_CARE || rrpd_list[i].state == state) + { + rrpd_index = i; + break; + } + } + } + } + return rrpd_index; +} + +void update_rrpd_list_entry(int match_index, RRPD *in_rrpd) +{ + null_output_rrpd_entries(&rrpd_list[match_index]); + + switch (rrpd_list[match_index].state) + { + case RRPD_STATE_1: + if (in_rrpd->c2s) + { + rrpd_list[match_index].req_last_frame = in_rrpd->req_last_frame; + rrpd_list[match_index].req_last_rtime = in_rrpd->req_last_rtime; + if (in_rrpd->msg_id) + { + rrpd_list[match_index].session_id = in_rrpd->session_id; + rrpd_list[match_index].msg_id = in_rrpd->msg_id; + rrpd_list[match_index].suffix = in_rrpd->suffix; + rrpd_list[match_index].state = RRPD_STATE_3; + } + } + else + { + rrpd_list[match_index].rsp_first_frame = in_rrpd->rsp_first_frame; + rrpd_list[match_index].rsp_first_rtime = in_rrpd->rsp_first_rtime; + rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame; + rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime; + if (in_rrpd->msg_id) + rrpd_list[match_index].state = RRPD_STATE_7; + else + rrpd_list[match_index].state = RRPD_STATE_5; + } + break; + + case RRPD_STATE_2: + if (in_rrpd->c2s) + { + rrpd_list[match_index].req_last_frame = in_rrpd->req_last_frame; + rrpd_list[match_index].req_last_rtime = in_rrpd->req_last_rtime; + if (in_rrpd->msg_id) + { + rrpd_list[match_index].session_id = in_rrpd->session_id; + rrpd_list[match_index].msg_id = in_rrpd->msg_id; + rrpd_list[match_index].suffix = in_rrpd->suffix; + rrpd_list[match_index].state = RRPD_STATE_4; + } + } + else + { + rrpd_list[match_index].rsp_first_frame = in_rrpd->rsp_first_frame; + rrpd_list[match_index].rsp_first_rtime = in_rrpd->rsp_first_rtime; + rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame; + rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime; + if (in_rrpd->msg_id) + rrpd_list[match_index].state = RRPD_STATE_8; + else + rrpd_list[match_index].state = RRPD_STATE_6; + } + break; + + case RRPD_STATE_3: + if (in_rrpd->c2s) + { + rrpd_list[match_index].req_last_frame = in_rrpd->req_last_frame; + rrpd_list[match_index].req_last_rtime = in_rrpd->req_last_rtime; + if (in_rrpd->msg_id) + { + rrpd_list[match_index].session_id = in_rrpd->session_id; + rrpd_list[match_index].msg_id = in_rrpd->msg_id; + rrpd_list[match_index].suffix = in_rrpd->suffix; + rrpd_list[match_index].state = RRPD_STATE_3; + } + } + else + { + rrpd_list[match_index].rsp_first_frame = in_rrpd->rsp_first_frame; + rrpd_list[match_index].rsp_first_rtime = in_rrpd->rsp_first_rtime; + rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame; + rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime; + if (in_rrpd->msg_id) + rrpd_list[match_index].state = RRPD_STATE_7; + else + rrpd_list[match_index].state = RRPD_STATE_5; + } + break; + + case RRPD_STATE_4: + if (in_rrpd->c2s) + { + rrpd_list[match_index].req_last_frame = in_rrpd->req_last_frame; + rrpd_list[match_index].req_last_rtime = in_rrpd->req_last_rtime; + if (in_rrpd->msg_id) + { + rrpd_list[match_index].session_id = in_rrpd->session_id; + rrpd_list[match_index].msg_id = in_rrpd->msg_id; + rrpd_list[match_index].suffix = in_rrpd->suffix; + rrpd_list[match_index].state = RRPD_STATE_4; + } + } + else + { + rrpd_list[match_index].rsp_first_frame = in_rrpd->rsp_first_frame; + rrpd_list[match_index].rsp_first_rtime = in_rrpd->rsp_first_rtime; + rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame; + rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime; + if (in_rrpd->msg_id) + rrpd_list[match_index].state = RRPD_STATE_8; + else + rrpd_list[match_index].state = RRPD_STATE_6; + } + break; + + case RRPD_STATE_5: + if (in_rrpd->c2s) + { + /* we've change direction */ + ; + } + else + { + rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame; + rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime; + if (in_rrpd->msg_id) + rrpd_list[match_index].state = RRPD_STATE_7; + else + rrpd_list[match_index].state = RRPD_STATE_5; + } + break; + + case RRPD_STATE_6: + if (in_rrpd->c2s) + { + /* we've change direction */ + ; + } + else + { + rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame; + rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime; + if (in_rrpd->msg_id) + rrpd_list[match_index].state = RRPD_STATE_8; + else + rrpd_list[match_index].state = RRPD_STATE_6; + } + break; + + case RRPD_STATE_7: + if (in_rrpd->c2s) + { + /* we've change direction */ + ; + } + else + { + rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame; + rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime; + } + break; + + case RRPD_STATE_8: + if (in_rrpd->c2s) + { + /* we've change direction */ + ; + } + else + { + rrpd_list[match_index].rsp_last_frame = in_rrpd->rsp_last_frame; + rrpd_list[match_index].rsp_last_rtime = in_rrpd->rsp_last_rtime; + } + break; + } + + update_output_rrpd(&rrpd_list[match_index]); +} + +/* + This function processes a sub-packet that is going from client-to-service. + */ +void update_rrpd_list_entry_req(RRPD *in_rrpd) +{ + int match_index = -1; + + if (in_rrpd->decode_based) + { + while (TRUE) + { + match_index = find_latest_rrpd(in_rrpd, RRPD_STATE_1); + if (match_index >= 0) /* Check to cover TCP Reassembly enabled */ + { + update_rrpd_list_entry(match_index, in_rrpd); + break; + } + + match_index = find_latest_rrpd(in_rrpd, RRPD_STATE_4); + if (match_index >= 0) + { + update_rrpd_list_entry(match_index, in_rrpd); + break; + } + + /* No entries and so add one */ + append_to_rrpd_list(in_rrpd); + break; + } + } + else + { + /* + This is not a decode_based calculation and so a change from s2c to c2s + means that this packets starts of a new APDU RR pair. + */ + match_index = find_latest_rrpd(in_rrpd, RRPD_STATE_DONT_CARE); + if (match_index >= 0) + { + if (rrpd_list[match_index].state > RRPD_STATE_4 && in_rrpd->c2s) + { + append_to_rrpd_list(in_rrpd); + } + else + /* no change of direction so just update the RTE data */ + update_rrpd_list_entry(match_index, in_rrpd); + } + else + { + append_to_rrpd_list(in_rrpd); + } + } + + return; +} + +/* + This function inserts an RRPD into the temp_rsp_rrpd_list. If this is + successful return the index of the entry. If there is no space return -1. + */ +int insert_into_temp_rsp_rrpd_list(RRPD *in_rrpd) +{ + int i; + + for (i = 0; i < SIZE_OF_TEMP_RSP_RRPD_LIST; i++) + { + if (temp_rsp_rrpd_list[i].ip_proto == 0) + break; + } + + if (temp_rsp_rrpd_list[i].ip_proto) + { + temp_rsp_rrpd_list[i] = *in_rrpd; + return i; + } + + return -1; +} + +int find_temp_rsp_rrpd(RRPD *in_rrpd) +{ + int entry_index = -1; + + for (int i = 0; i < SIZE_OF_TEMP_RSP_RRPD_LIST; i++) + { + if (temp_rsp_rrpd_list[i].ip_proto == in_rrpd->ip_proto && temp_rsp_rrpd_list[i].stream_no == in_rrpd->stream_no) + { + entry_index = i; + break; + } + } + return entry_index; +} + +void update_temp_rsp_rrpd(int temp_list_index, RRPD *in_rrpd) +{ + temp_rsp_rrpd_list[temp_list_index].rsp_last_frame = in_rrpd->rsp_last_frame; + temp_rsp_rrpd_list[temp_list_index].rsp_last_rtime = in_rrpd->rsp_last_rtime; +} + +/* This function migrates an entry from the temp_rsp_rrpd_list to the main rrpd_list. */ +void migrate_temp_rsp_rrpd(int main_list_index, int temp_list_index) +{ + update_rrpd_list_entry(main_list_index, &(temp_rsp_rrpd_list[temp_list_index])); + + clear_rrpd(&temp_rsp_rrpd_list[temp_list_index]); + + /* Update the state to 7 or 8 based on reassembly */ + if (preferences.reassembly) + rrpd_list[main_list_index].state = RRPD_STATE_7; + else + rrpd_list[main_list_index].state = RRPD_STATE_8; + + return; +} + +void update_rrpd_list_entry_rsp(RRPD *in_rrpd) +{ + int match_index = -1; + + if (in_rrpd->decode_based) + { + if (preferences.reassembly) + { + if (in_rrpd->msg_id) + { + /* If we have a msg_id in the input RRPD we must have header information. */ + int temp_list_index = find_temp_rsp_rrpd(in_rrpd); + + if (temp_list_index >= 0) + { + update_temp_rsp_rrpd(temp_list_index, in_rrpd); + + /* Migrate the temp_rsp_rrpd_list entry to the main rrpd_list */ + match_index = find_latest_rrpd(in_rrpd, RRPD_STATE_3); + if (match_index >= 0) + migrate_temp_rsp_rrpd(match_index, temp_list_index); + } + else + { + match_index = find_latest_rrpd(in_rrpd, RRPD_STATE_3); + /* There isn't an entry in the temp_rsp_rrpd_list so update the master rrpd_list entry */ + if (match_index >= 0) + update_rrpd_list_entry(match_index, in_rrpd); + } + } + else + { + /* Update an existing entry to the temp_rsp_rrpd_list or add a new one. */ + int temp_list_index = find_temp_rsp_rrpd(in_rrpd); + + if (temp_list_index >= 0) + update_temp_rsp_rrpd(temp_list_index, in_rrpd); + else + insert_into_temp_rsp_rrpd_list(in_rrpd); + } + } + else + { + /* Reassembly isn't set and so just go ahead and use the list function */ + match_index = find_latest_rrpd(in_rrpd, RRPD_STATE_8); + if (match_index >= 0) + update_rrpd_list_entry(match_index, in_rrpd); + } + } + else + { + /* if this isn't decode_based then just go ahead and update the RTE data */ + match_index = find_latest_rrpd(in_rrpd, RRPD_STATE_DONT_CARE); + update_rrpd_list_entry(match_index, in_rrpd); + } + + return; +} + + +/* + This function updates the RTE data of an RRPD on the rrpd_list. The + frame_no values in the input RRPD double up as a mask. If the frame_no + is > 0 then the frame_no value and rtime values are updated. If the + frame_no is 0 then that particular frame_no and rtime value is not updated. + */ +void update_rrpd_rte_data(RRPD *in_rrpd) +{ + if (in_rrpd->c2s) + update_rrpd_list_entry_req(in_rrpd); + else + update_rrpd_list_entry_rsp(in_rrpd); +} + +/* This function initialises all of the sub_packets in the sub_packet array. */ +void init_sub_packet() +{ + for (int i = 0; i < MAX_SUBPKTS_PER_PACKET; i++) + { + sub_packet[i].frame_number = 0; + sub_packet[i].relative_time.secs = 0; + sub_packet[i].relative_time.nsecs = 0; + + sub_packet[i].tcp_retran = FALSE; + sub_packet[i].tcp_keep_alive = FALSE; + sub_packet[i].tcp_flags_syn = FALSE; + sub_packet[i].tcp_flags_ack = FALSE; + sub_packet[i].tcp_flags_reset = FALSE; + sub_packet[i].tcp_flags_urg = FALSE; + sub_packet[i].tcp_seq = 0; + + sub_packet[i].srcport = 0; + sub_packet[i].dstport = 0; + sub_packet[i].len = 0; + + sub_packet[i].tds_type = 0; + sub_packet[i].tds_length = 0; + + sub_packet[i].smb2_msg_id = 0; + sub_packet[i].smb2_sesid = 0; + sub_packet[i].smb2_cmd = 0; + + sub_packet[i].smb_mid = 0; + + sub_packet[i].dcerpc_ver = 0; + sub_packet[i].dcerpc_pkt_type = 0; + sub_packet[i].dcerpc_cn_call_id = 0; + sub_packet[i].dcerpc_cn_ctx_id = 0; + + sub_packet[i].dns_id = 0; + + sub_packet[i].pkt_of_interest = FALSE; + sub_packet[i].rrpd.c2s = FALSE; + sub_packet[i].rrpd.state = RRPD_STATE_INIT; + + clear_rrpd(&sub_packet[i].rrpd); + } + + return; +} + +void set_pkt_rrpd(PKT_INFO *current_pkt, guint8 ip_proto, guint32 stream_no, guint64 session_id, guint64 msg_id, gboolean requires_suffix) +{ + current_pkt->rrpd.ip_proto = ip_proto; + current_pkt->rrpd.stream_no = stream_no; + current_pkt->rrpd.session_id = session_id; + current_pkt->rrpd.msg_id = msg_id; + + if (requires_suffix) + current_pkt->rrpd.suffix = ++rrpd_suffix; + else + current_pkt->rrpd.suffix = 0; + + return; +} + + +/* + This function initialises the global variables and populates the + tcp_svc_port table with information from the preference settings + */ +void init_globals(void) +{ + /* The following achives two things; a) we avoid double registering the fake tap + and b) we discard the fake tap when the "TRANSUM enabled" preference is changed. + + We remove the tap when it is not needed as it has a performance impact. + + It's safe to call remove_tap_listener even if the tap listener doesn't exist. + If it doesn't find &fake_tap on the queue of listeners it calls the actual freeing + function with a pointer of NULL and the called function just returns. */ + remove_tap_listener(&fake_tap); + + if (!preferences.tsumenabled) return; + + /* Create and initialise some dynamic memory areas */ + detected_tcp_svc = (gboolean *)wmem_alloc(wmem_file_scope(), (64 * 1024 * sizeof(gboolean))); + sub_packet = (PKT_INFO *)wmem_alloc(wmem_file_scope(), (MAX_SUBPKTS_PER_PACKET * sizeof(PKT_INFO))); + rrpd_list = (RRPD *)wmem_alloc(wmem_file_scope(), (MAX_RRPDS * sizeof(RRPD))); + temp_rsp_rrpd_list = (RRPD *)wmem_alloc(wmem_file_scope(), (SIZE_OF_TEMP_RSP_RRPD_LIST * sizeof(RRPD))); + + memset(detected_tcp_svc, 0x00, (64 * 1024 * sizeof(gboolean))); + memset(sub_packet, 0x00, (MAX_SUBPKTS_PER_PACKET * sizeof(PKT_INFO))); + memset(rrpd_list, 0x00, (MAX_RRPDS * sizeof(RRPD))); + memset(temp_rsp_rrpd_list, 0x00, (SIZE_OF_TEMP_RSP_RRPD_LIST * sizeof(RRPD))); + + next_free_rrpd = 0; + + GString* fake_tap_filter = g_string_new("frame"); + + /* ToDo: the following and the hf_of_interest mechanism above should be replaced by something array-based so that + it is easier to extend. */ + g_string_append_printf(fake_tap_filter, " || eth.type"); + g_string_append_printf(fake_tap_filter, " || ip.proto"); + g_string_append_printf(fake_tap_filter, " || ipv6.nxt"); + g_string_append_printf(fake_tap_filter, " || tcp.srcport"); + g_string_append_printf(fake_tap_filter, " || tcp.dstport"); + g_string_append_printf(fake_tap_filter, " || tcp.stream"); + g_string_append_printf(fake_tap_filter, " || tcp.analysis.retransmission"); + g_string_append_printf(fake_tap_filter, " || tcp.analysis.keep_alive"); + g_string_append_printf(fake_tap_filter, " || tcp.len"); + g_string_append_printf(fake_tap_filter, " || tcp.flags.syn"); + g_string_append_printf(fake_tap_filter, " || tcp.flags.ack"); + g_string_append_printf(fake_tap_filter, " || tcp.flags.reset"); + g_string_append_printf(fake_tap_filter, " || tcp.urgent_pointer"); + g_string_append_printf(fake_tap_filter, " || tcp.seq"); + + g_string_append_printf(fake_tap_filter, " || tds.type"); + g_string_append_printf(fake_tap_filter, " || tds.length"); + + g_string_append_printf(fake_tap_filter, " || udp.srcport"); + g_string_append_printf(fake_tap_filter, " || udp.dstport"); + g_string_append_printf(fake_tap_filter, " || udp.stream"); + g_string_append_printf(fake_tap_filter, " || udp.length"); + + g_string_append_printf(fake_tap_filter, " || smb2.msg_id"); + g_string_append_printf(fake_tap_filter, " || smb2.sesid"); + g_string_append_printf(fake_tap_filter, " || smb2.cmd"); + + g_string_append_printf(fake_tap_filter, " || smb.mid"); + + g_string_append_printf(fake_tap_filter, " || dcerpc.ver"); + g_string_append_printf(fake_tap_filter, " || dcerpc.pkt_type"); + g_string_append_printf(fake_tap_filter, " || dcerpc.cn_ctx_id"); + g_string_append_printf(fake_tap_filter, " || dcerpc.cn_call_id"); + + g_string_append_printf(fake_tap_filter, " || dns.id"); + + /* this fake tap is needed to force WS to pass a tree to the dissectors on + the first scan which causes the dissectors to create display filter values + which are then available to TRANSUM during the first scan */ + GString* error = register_tap_listener("frame", + &fake_tap, + fake_tap_filter->str, + TL_REQUIRES_NOTHING, + NULL, NULL, NULL); /* NULL pointers as this is a fake tap */ + + if (error) + { + report_failure("register_tap_listener() failed"); + return; + } + + g_string_free(fake_tap_filter, TRUE); + + /* use the range values to populate the tcp_svc_port list*/ + for (guint i = 0; i < tcp_svc_port_range_values->nranges; i++) + { + for (guint32 j = tcp_svc_port_range_values->ranges[i].low; j <= tcp_svc_port_range_values->ranges[i].high; j++) + { + preferences.tcp_svc_port[j] = RTE_CALC_GTCP; + } + } + + /* use the range values to populate the tcp_svc_port list*/ + for (guint i = 0; i < udp_svc_port_range_values->nranges; i++) + { + for (guint32 j = udp_svc_port_range_values->ranges[i].low; j <= udp_svc_port_range_values->ranges[i].high; j++) + { + preferences.udp_svc_port[j] = RTE_CALC_GUDP; + } + } + + init_detected_tcp_svc(); + init_dcerpc_data(); + + preferences.tcp_svc_port[445] = RTE_CALC_SMB2; + preferences.udp_svc_port[53] = RTE_CALC_DNS; + + init_rrpd_data(); + +} + +/* This function adds the RTE data to the tree. The summary ptr is currently + not used but will be used for summariser information once this feature has + been ported from the LUA code. */ +void write_rte(RRPD *in_rrpd, tvbuff_t *tvb, proto_tree *tree, char *summary) +{ + nstime_t rte_art; + nstime_t rte_st; + nstime_t rte_reqspread; + nstime_t rte_rspspread; + proto_tree *rte_tree; + proto_item *pi; + + char *temp_string; + temp_string = wmem_alloc(wmem_packet_scope(), SIZEOF_TEMP_STRING); + + if (in_rrpd->req_first_frame) + { + nstime_delta(&rte_reqspread, &(in_rrpd->req_last_rtime), &(in_rrpd->req_first_rtime)); + + if (in_rrpd->rsp_first_frame) + { + /* calculate the RTE times */ + nstime_delta(&rte_art, &(in_rrpd->rsp_last_rtime), &(in_rrpd->req_first_rtime)); + nstime_delta(&rte_st, &(in_rrpd->rsp_first_rtime), &(in_rrpd->req_last_rtime)); + nstime_delta(&rte_rspspread, &(in_rrpd->rsp_last_rtime), &(in_rrpd->rsp_first_rtime)); + + g_snprintf(temp_string, SIZEOF_TEMP_STRING, "OK"); + } + else + g_snprintf(temp_string, SIZEOF_TEMP_STRING, "Response missing"); + + pi = proto_tree_add_item(tree, proto_transum, tvb, 0, -1, ENC_NA); + rte_tree = proto_item_add_subtree(pi, ett_transum); + + pi = proto_tree_add_string(rte_tree, hf_tsum_status, tvb, 0, 0, temp_string); + PROTO_ITEM_SET_GENERATED(pi); + + pi = proto_tree_add_uint(rte_tree, hf_tsum_req_first_seg, tvb, 0, 0, in_rrpd->req_first_frame); + PROTO_ITEM_SET_GENERATED(pi); + pi = proto_tree_add_uint(rte_tree, hf_tsum_req_last_seg, tvb, 0, 0, in_rrpd->req_last_frame); + PROTO_ITEM_SET_GENERATED(pi); + + if (in_rrpd->rsp_first_frame) + { + pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_first_seg, tvb, 0, 0, in_rrpd->rsp_first_frame); + PROTO_ITEM_SET_GENERATED(pi); + pi = proto_tree_add_uint(rte_tree, hf_tsum_rsp_last_seg, tvb, 0, 0, in_rrpd->rsp_last_frame); + PROTO_ITEM_SET_GENERATED(pi); + + pi = proto_tree_add_time(rte_tree, hf_tsum_apdu_rsp_time, tvb, 0, 0, &rte_art); + PROTO_ITEM_SET_GENERATED(pi); + pi = proto_tree_add_time(rte_tree, hf_tsum_service_time, tvb, 0, 0, &rte_st); + PROTO_ITEM_SET_GENERATED(pi); + } + + pi = proto_tree_add_time(rte_tree, hf_tsum_req_spread, tvb, 0, 0, &rte_reqspread); + PROTO_ITEM_SET_GENERATED(pi); + + if (in_rrpd->rsp_first_frame) + { + pi = proto_tree_add_time(rte_tree, hf_tsum_rsp_spread, tvb, 0, 0, &rte_rspspread); + PROTO_ITEM_SET_GENERATED(pi); + } + + if (in_rrpd->ip_proto == IP_PROTO_TCP) + g_snprintf(temp_string, SIZEOF_TEMP_STRING, "tcp.stream==%d", in_rrpd->stream_no); + else if (in_rrpd->ip_proto == IP_PROTO_UDP) + g_snprintf(temp_string, SIZEOF_TEMP_STRING, "udp.stream==%d", in_rrpd->stream_no); + + if (in_rrpd->rsp_first_frame) + g_snprintf(temp_string, SIZEOF_TEMP_STRING, "%s && frame.number>=%d && frame.number<=%d", temp_string, in_rrpd->req_first_frame, in_rrpd->rsp_last_frame); + else + g_snprintf(temp_string, SIZEOF_TEMP_STRING, "%s && frame.number>=%d && frame.number<=%d", temp_string, in_rrpd->req_first_frame, in_rrpd->req_last_frame); + + if (in_rrpd->calculation == RTE_CALC_GTCP) + g_snprintf(temp_string, SIZEOF_TEMP_STRING, "%s && tcp.len>0", temp_string); + + pi = proto_tree_add_string(rte_tree, hf_tsum_clip_filter, tvb, 0, 0, temp_string); + PROTO_ITEM_SET_GENERATED(pi); + + switch (in_rrpd->calculation) + { + case RTE_CALC_GTCP: + g_snprintf(temp_string, SIZEOF_TEMP_STRING, "Generic TCP"); + break; + + case RTE_CALC_SYN: + g_snprintf(temp_string, SIZEOF_TEMP_STRING, "SYN and SYN/ACK"); + break; + + case RTE_CALC_DCERPC: + g_snprintf(temp_string, SIZEOF_TEMP_STRING, "DCE-RPC"); + break; + + case RTE_CALC_SMB2: + g_snprintf(temp_string, SIZEOF_TEMP_STRING, "SMB2"); + break; + + case RTE_CALC_GUDP: + g_snprintf(temp_string, SIZEOF_TEMP_STRING, "Generic UDP"); + break; + + case RTE_CALC_DNS: + g_snprintf(temp_string, SIZEOF_TEMP_STRING, "DNS"); + break; + + default: + g_snprintf(temp_string, SIZEOF_TEMP_STRING, "Unknown calculation type: %d", in_rrpd->calculation); + break; + } + pi = proto_tree_add_string(rte_tree, hf_tsum_calculation, tvb, 0, 0, temp_string); + PROTO_ITEM_SET_GENERATED(pi); + + if (in_rrpd->rsp_first_frame) + { + if (preferences.summarisers_enabled) + { + if (summary) + { + pi = proto_tree_add_string(tree, hf_tsum_summary, tvb, 0, 0, summary); + PROTO_ITEM_SET_GENERATED(pi); + } + } + } + } +} + +/* + This function sets initial values in the current_pkt structure and checks + the xxx_svc_port arrays to see if they conatin a match for the source or + destination port. This function also adds tcp_svc_port entries when it + discovers DCE-RPC traffic. + + Returns the number of sub-packets to be processed. +*/ +void set_proto_values(packet_info *pinfo, proto_tree *tree) +{ + guint32 field_uint[MAX_RETURNED_ELEMENTS]; /* An extracted field array for unsigned integers */ + size_t field_value_count; /* How many entries are there in the extracted field array */ + + sub_packet[0].frame_number = pinfo->fd->num; /* easy access to frame number */ + sub_packet[0].relative_time = pinfo->rel_ts; + + int number_sub_pkts_of_interest = 0; /* default */ + + if (pinfo->ptype == PT_TCP) + sub_packet[0].rrpd.ip_proto = IP_PROTO_TCP; + else if (pinfo->ptype == PT_UDP) + sub_packet[0].rrpd.ip_proto = IP_PROTO_UDP; + + if (sub_packet[0].rrpd.ip_proto == IP_PROTO_TCP) + { + number_sub_pkts_of_interest = decode_gtcp(pinfo, tree); + /* decode_gtcp may return 0 but we need to keep processing because we + calculate RTE figures for all SYNs and also we may detect DCE-RPC later + (even though we don't currently have an entry in the tcp_svc_port list). */ + + if (sub_packet[0].tcp_retran) + { + /* we may not want to continue with this packet if it's a retransmission */ + + /* If this is a server-side trace we need to ignore client-to-service TCP retransmissions + the rationale being that if we saw the original in the trace the service process saw it too */ + if (sub_packet[0].rrpd.c2s && preferences.capture_position == CAPTURE_SERVICE) + { + sub_packet[0].pkt_of_interest = FALSE; + return; + } + + /* If this is a client-side trace we need to ignore service-to-client TCP retransmissions + the rationale being that if we saw the original in the trace the client process saw it too */ + else if (!sub_packet[0].rrpd.c2s && preferences.capture_position == CAPTURE_CLIENT) + { + sub_packet[0].pkt_of_interest = FALSE; + return; + } + } + + /* We are not interested in TCP Keep-Alive */ + if (sub_packet[0].tcp_keep_alive) + { + sub_packet[0].pkt_of_interest = FALSE; + return; + } + + if (sub_packet[0].len == 1) + { + if (preferences.orphan_ka_discard && sub_packet[0].tcp_flags_ack && sub_packet[0].rrpd.c2s) + { + sub_packet[0].pkt_of_interest = FALSE; + return; /* It's a KEEP-ALIVE -> stop processing this packet */ + } + } + + /* check if SYN */ + if (sub_packet[0].tcp_flags_syn) + number_sub_pkts_of_interest = decode_syn(pinfo, tree); + + if (sub_packet[0].len > 0) + { + /* check if SMB2 */ + if (sub_packet[0].dstport == 445 || sub_packet[0].srcport == 445) + number_sub_pkts_of_interest = decode_smb(pinfo, tree); + + /* check if DCE-RPC */ + else if (!extract_uint(tree, hf_of_interest.dcerpc_ver, field_uint, &field_value_count)) + { + if (field_value_count) + number_sub_pkts_of_interest = decode_dcerpc(pinfo, tree); + } + } + + } + else if (sub_packet[0].rrpd.ip_proto == IP_PROTO_UDP) + { + /* It's UDP */ + number_sub_pkts_of_interest = decode_gudp(pinfo, tree); + + if (sub_packet[0].srcport == 53 || sub_packet[0].dstport == 53) + number_sub_pkts_of_interest = decode_dns(pinfo, tree); + } + + /* Set appropriate RTE values in the sub-packets */ + for (int i = 0; i < number_sub_pkts_of_interest; i++) + { + if (sub_packet[0].rrpd.c2s) + { + sub_packet[i].rrpd.req_first_frame = sub_packet[0].frame_number; + sub_packet[i].rrpd.req_first_rtime = sub_packet[0].relative_time; + sub_packet[i].rrpd.req_last_frame = sub_packet[0].frame_number; + sub_packet[i].rrpd.req_last_rtime = sub_packet[0].relative_time; + + sub_packet[i].frame_number = sub_packet[0].frame_number; /* this acts as a switch later */ + } + else + { + sub_packet[i].rrpd.rsp_first_frame = sub_packet[0].frame_number; + sub_packet[i].rrpd.rsp_first_rtime = sub_packet[0].relative_time; + sub_packet[i].rrpd.rsp_last_frame = sub_packet[0].frame_number; + sub_packet[i].rrpd.rsp_last_rtime = sub_packet[0].relative_time; + + sub_packet[i].frame_number = sub_packet[0].frame_number; /* this acts as a switch later */ + } + } +} + + +/* + * This function is called for each packet + * Wireshark scans all the packets once and then once again as they are displayed + * The pinfo.visited boolean is set to FALSE; on the first scan +*/ +static int dissect_transum(tvbuff_t *buffer, packet_info *pinfo, proto_tree *tree _U_) +{ + if (!preferences.tsumenabled) return 0; + + /* if (there is RTE info associated with this packet we need to output it */ + if (PINFO_FD_VISITED(pinfo)) + { + RRPD *rrpd = output_rrpd[pinfo->num]; + + if (rrpd) + /* Add the RTE data to the protocol decode tree if we output_flag is set */ + write_rte(rrpd, buffer, tree, NULL); + } + else + { + init_sub_packet(); + + set_proto_values(pinfo, tree); + + if (sub_packet[0].pkt_of_interest) + { + /* Loop to process each sub_packet and update the related RTE data */ + for (int i = 0; i < MAX_SUBPKTS_PER_PACKET; i++) + { + if (!sub_packet[i].frame_number) + break; + + update_rrpd_rte_data(&(sub_packet[i].rrpd)); + } + } + } + + return 0; +} + +void +proto_register_transum(void) +{ + module_t *transum_module; + dissector_handle_t transum_handle; + + static hf_register_info hf[] = { + { &hf_tsum, + { "TRANSUM", "transum", + FT_NONE, BASE_NONE, NULL, 0x0, + "Post-dissector to generate RTE information", HFILL } }, + + { &hf_tsum_status, + { "RTE Status", "transum.status", + FT_STRING, BASE_NONE, NULL, 0x0, + "Indication of completeness of the RTE information", HFILL } }, + + { &hf_tsum_time_units, + { "RTE Time Units", "transum.time_units", + FT_STRING, BASE_NONE, NULL, 0x0, + "Time units used (s, ms or us) for the RTE values", HFILL } + }, + + { &hf_tsum_req_first_seg, + { "Req First Seg", "transum.firstreq", + FT_FRAMENUM, BASE_NONE, NULL, 0x0, + "First Segment of an APDU Request", HFILL } + }, + + { &hf_tsum_req_last_seg, + { "Req Last Seg", "transum.lastreq", + FT_FRAMENUM, BASE_NONE, NULL, 0x0, + "Last Segment of an APDU Request", HFILL } + }, + + { &hf_tsum_rsp_first_seg, + { "Rsp First Seg", "transum.firstrsp", + FT_FRAMENUM, BASE_NONE, NULL, 0x0, + "First Segment of an APDU Response", HFILL } + }, + + { &hf_tsum_rsp_last_seg, + { "Rsp Last Seg", "transum.lastrsp", + FT_FRAMENUM, BASE_NONE, NULL, 0x0, + "Last Segment of an APDU Response", HFILL } + }, + + { &hf_tsum_apdu_rsp_time, + { "APDU Rsp Time", "transum.art", + FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, + "RTE APDU Response Time", HFILL } + }, + + { &hf_tsum_service_time, + { "Service Time", "transum.st", + FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, + "RTE Service Time", HFILL } + }, + + { &hf_tsum_req_spread, + { "Req Spread", "transum.reqspread", + FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, + "RTE Request Spread", HFILL } + }, + + { &hf_tsum_rsp_spread, + { "Rsp Spread", "transum.rspspread", + FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, + "RTE Response Spread", HFILL } + }, + + { &hf_tsum_clip_filter, + { "Trace clip filter", "transum.clip_filter", + FT_STRING, BASE_NONE, NULL, 0x0, + "Filter expression to select the APDU Reqest-Response pair", HFILL } + }, + + { &hf_tsum_calculation, + { "Calculation", "transum.calculation", + FT_STRING, BASE_NONE, NULL, 0x0, + "Basis of the RTE calculation", HFILL } + }, + + { &hf_tsum_summary, + { "Summary", "transum.summary", + FT_STRING, BASE_NONE, NULL, 0x0, + "Summarizer information", HFILL } + } + }; + + /* Setup protocol subtree array */ + static gint *ett[] = { + &ett_transum, + &ett_transum_header, + &ett_transum_data + }; + + proto_transum = proto_register_protocol( + "TRANSUM RTE Data", /* name */ + "TRANSUM", /* short name */ + "transum" /* abbrev */ + ); + + /* Set User Preferences defaults */ + preferences.tsumenabled = FALSE; + preferences.capture_position = TRACE_CAP_CLIENT; + preferences.reassembly = TRUE; + + tcp_svc_port_range_values = (range_t *)g_malloc((sizeof(guint) + (4 * sizeof(range_admin_t)))); + tcp_svc_port_range_values->nranges = 4; + tcp_svc_port_range_values->ranges[0].low = 25; + tcp_svc_port_range_values->ranges[0].high = 25; + tcp_svc_port_range_values->ranges[1].low = 80; + tcp_svc_port_range_values->ranges[1].high = 80; + tcp_svc_port_range_values->ranges[2].low = 443; + tcp_svc_port_range_values->ranges[2].high = 443; + tcp_svc_port_range_values->ranges[3].low = 1433; + tcp_svc_port_range_values->ranges[3].high = 1433; + + udp_svc_port_range_values = (range_t *)g_malloc((sizeof(guint) + (1 * sizeof(range_admin_t)))); + udp_svc_port_range_values->nranges = 1; + udp_svc_port_range_values->ranges[0].low = 137; + udp_svc_port_range_values->ranges[0].high = 139; + + preferences.orphan_ka_discard = FALSE; + preferences.time_multiplier = RTE_TIME_SEC; + preferences.rte_on_first_req = FALSE; + preferences.rte_on_last_req = TRUE; + preferences.rte_on_first_rsp = FALSE; + preferences.rte_on_last_rsp = FALSE; + + /* create arrays to hold some DCE-RPC values */ + dcerpc_req_pkt_type = (gboolean *)wmem_alloc(wmem_epan_scope(), (256 * sizeof(gboolean))); + dcerpc_context_zero = (gboolean *)wmem_alloc(wmem_epan_scope(), (256 * sizeof(gboolean))); + + /* no start registering stuff */ + proto_register_field_array(proto_transum, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + transum_module = prefs_register_protocol(proto_transum, NULL); /* ToDo: We need to rethink the NULL pointer so that a preference change causes a rescan */ + + /* Register the preferences */ + prefs_register_bool_preference(transum_module, "tsumenabled", + "TRANSUM enabled", + "Uncheck to bypass TRANSUM", + &preferences.tsumenabled); + + prefs_register_enum_preference(transum_module, + "capture_position", + "Capture position", + "Position of the capture unit that produced this trace. This setting affects the way TRANSUM handles TCP Retransmissions. See the manual for details.", + &preferences.capture_position, + capture_position_vals, + FALSE); + + prefs_register_bool_preference(transum_module, + "reassembly", + "Subdissector reassembly enabled", + "Set this to match to the TCP subdissector reassembly setting", + &preferences.reassembly); + + prefs_register_range_preference(transum_module, + "tcp_port_ranges", + "Output RTE data for these TCP service ports", + "Add and remove ports numbers separated by commas\nRanges are supported e.g. 25,80,2000-3000,5432", + &tcp_svc_port_range_values, + 65536); + + prefs_register_range_preference(transum_module, + "udp_port_ranges", + "Output RTE data for these UDP service ports", + "Add and remove ports numbers separated by commas\nRanges are supported e.g. 123,137-139,520-521,2049", + &udp_svc_port_range_values, + 65536); + + prefs_register_bool_preference(transum_module, + "orphan_ka_discard", + "Discard orphaned TCP Keep-Alives", + "Set this to discard any packet in the direction client to service,\nwith a 1-byte payload of 0x00 and the ACK flag set", + &preferences.orphan_ka_discard); + + /* removed from this release + prefs_register_enum_preference(transum_module, + "time_multiplier", + "Time units for RTE values", + "Unit of time used for APDU Response Time, Service Time and Spread Time values.", + &preferences.time_multiplier, + time_multiplier_vals, + FALSE); + */ + + prefs_register_bool_preference(transum_module, + "rte_on_first_req", + "Add RTE data to the first request segment", + "RTE data will be added to the first request packet", + &preferences.rte_on_first_req); + + prefs_register_bool_preference(transum_module, + "rte_on_last_req", + "Add RTE data to the last request segment", + "RTE data will be added to the last request packet", + &preferences.rte_on_last_req); + + prefs_register_bool_preference(transum_module, + "rte_on_first_rsp", + "Add RTE data to the first response segment", + "RTE data will be added to the first response packet", + &preferences.rte_on_first_rsp); + + prefs_register_bool_preference(transum_module, + "rte_on_last_rsp", + "Add RTE data to the last response segment", + "RTE data will be added to the last response packet", + &preferences.rte_on_last_rsp); + + transum_handle = register_dissector("transum", dissect_transum, proto_transum); + + transum_module = prefs_register_protocol(proto_transum, proto_reg_handoff_transum); + register_init_routine(init_globals); + + register_postdissector(transum_handle); +} + +void proto_reg_handoff_transum(void) +{ + /* Get the field id for each field we will need */ + hf_of_interest.ip_proto = proto_registrar_get_id_byname("ip.proto"); + hf_of_interest.ipv6_nxt = proto_registrar_get_id_byname("ipv6.nxt"); + hf_of_interest.tcp_retran = proto_registrar_get_id_byname("tcp.analysis.retransmission"); + hf_of_interest.tcp_keep_alive = proto_registrar_get_id_byname("tcp.analysis.keep_alive"); + hf_of_interest.tcp_flags_syn = proto_registrar_get_id_byname("tcp.flags.syn"); + hf_of_interest.tcp_flags_ack = proto_registrar_get_id_byname("tcp.flags.ack"); + hf_of_interest.tcp_flags_reset = proto_registrar_get_id_byname("tcp.flags.reset"); + hf_of_interest.tcp_flags_urg = proto_registrar_get_id_byname("tcp.flags.urg"); + hf_of_interest.tcp_seq = proto_registrar_get_id_byname("tcp.seq"); + hf_of_interest.tcp_srcport = proto_registrar_get_id_byname("tcp.srcport"); + hf_of_interest.tcp_dstport = proto_registrar_get_id_byname("tcp.dstport"); + hf_of_interest.tcp_stream = proto_registrar_get_id_byname("tcp.stream"); + hf_of_interest.tcp_len = proto_registrar_get_id_byname("tcp.len"); + + hf_of_interest.udp_srcport = proto_registrar_get_id_byname("udp.srcport"); + hf_of_interest.udp_dstport = proto_registrar_get_id_byname("udp.dstport"); + hf_of_interest.udp_stream = proto_registrar_get_id_byname("udp.stream"); + hf_of_interest.udp_length = proto_registrar_get_id_byname("udp.length"); + + hf_of_interest.tds_type = proto_registrar_get_id_byname("tds.type"); + hf_of_interest.tds_length = proto_registrar_get_id_byname("tds.length"); + + hf_of_interest.smb_mid = proto_registrar_get_id_byname("smb.mid"); + + hf_of_interest.smb2_ses_id = proto_registrar_get_id_byname("smb2.sesid"); + hf_of_interest.smb2_msg_id = proto_registrar_get_id_byname("smb2.msg_id"); + hf_of_interest.smb2_cmd = proto_registrar_get_id_byname("smb2.msg_cmd"); + + hf_of_interest.dcerpc_ver = proto_registrar_get_id_byname("dcerpc.ver"); + hf_of_interest.dcerpc_pkt_type = proto_registrar_get_id_byname("dcerpc.pkt_type"); + hf_of_interest.dcerpc_cn_call_id = proto_registrar_get_id_byname("dcerpc.cn_call_id"); + hf_of_interest.dcerpc_cn_ctx_id = proto_registrar_get_id_byname("dcerpc.cn_ctx_id"); + + hf_of_interest.dns_id = proto_registrar_get_id_byname("dns.id"); + + if (!preferences.tsumenabled) + proto_disable_by_default(proto_transum); + proto_set_decoding(proto_transum, preferences.tsumenabled); +} diff --git a/plugins/transum/packet-transum.h b/plugins/transum/packet-transum.h new file mode 100644 index 0000000000..992d3a3249 --- /dev/null +++ b/plugins/transum/packet-transum.h @@ -0,0 +1,185 @@ +/* packet-transum.h +* Header file for the TRANSUM response time analyzer post-dissector +* By Paul Offord +* Copyright 2016 Advance Seven Limited +* +* Wireshark - Network traffic analyzer +* By Gerald Combs +* Copyright 1998 Gerald Combs +* +* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#define ETH_TYPE_IPV4 0x0800 +#define ETH_TYPE_IPV6 0x86dd + +#define IP_PROTO_TCP 6 +#define IP_PROTO_UDP 17 + +#define RRPD_STATE_DONT_CARE 0 +#define RRPD_STATE_INIT 0 +#define RRPD_STATE_1 1 +#define RRPD_STATE_2 2 +#define RRPD_STATE_3 3 +#define RRPD_STATE_4 4 +#define RRPD_STATE_5 5 +#define RRPD_STATE_6 6 +#define RRPD_STATE_7 7 +#define RRPD_STATE_8 8 + +#define RTE_CALC_SYN 1 +#define RTE_CALC_GTCP 2 +#define RTE_CALC_GUDP 3 +#define RTE_CALC_SMB1 4 +#define RTE_CALC_SMB2 5 +#define RTE_CALC_DCERPC 6 +#define RTE_CALC_DNS 7 + +#define RRPD_SIZE 64 + +#define MAX_STREAMS_PER_PROTOCOL 256*1024 +#define MAX_PACKETS 8000000 /* We support 8 million packets */ +#define MAX_SUBPKTS_PER_PACKET 16 +#define MAX_RRPDS 1000000 /* We support 4 million RRPDs */ +#define SIZE_OF_TEMP_RSP_RRPD_LIST 1024 + +/* + An RR pair is identified by a Fully Qualified Message ID (RRPD) +*/ + +typedef struct _RRPD +{ + /* + When a c2s is set TRUE it means that the associated packet is going from + client-to-service. If this value is false the associated packet is going + from service-to-client. + + This value is only valid for RRPDs imbedded in subpacket structures. + */ + gboolean c2s; + + guint8 ip_proto; + guint32 stream_no; + guint64 session_id; + guint64 msg_id; + guint32 suffix; + + /* + Some request-response pairs are demarked simple by a change in direction on a + TCP or UDP stream from s2c to c2s. This is true for the GTCP and GUDP + calculations. Other calculations (such as DCERPC) use application protocol + values to detect the start and end of APDUs. In this latter case decode_based + is set to true. + */ + gboolean decode_based; + + int state; + + guint32 req_first_frame; + nstime_t req_first_rtime; + guint32 req_last_frame; + nstime_t req_last_rtime; + + guint32 rsp_first_frame; + nstime_t rsp_first_rtime; + guint32 rsp_last_frame; + nstime_t rsp_last_rtime; + + guint calculation; +} RRPD; + +typedef struct _PKT_INFO +{ + int frame_number; + nstime_t relative_time; + + gboolean tcp_retran; /* tcp.analysis.retransmission */ + gboolean tcp_keep_alive; /* tcp.analysis.keep_alive */ + gboolean tcp_flags_syn; /* tcp.flags.syn */ + gboolean tcp_flags_ack; /* tcp.flags.ack */ + gboolean tcp_flags_reset; /* tcp.flags.reset */ + guint32 tcp_flags_urg; /* tcp.urgent_pointer */ + guint32 tcp_seq; /* tcp.seq */ + + /* Generic transport values */ + guint16 srcport; /* tcp.srcport or udp.srcport*/ + guint16 dstport; /* tcp.dstport or udp.dstport*/ + guint16 len; /* tcp.len or udp.len */ + + guint8 tds_type; /*tds.type */ + guint16 tds_length; /* tds.length */ + + guint16 smb_mid; /* smb.mid */ + + guint64 smb2_sesid; /* smb2.sesid */ + guint64 smb2_msg_id; /* smb2.msg_id */ + guint16 smb2_cmd; /* smb2.cmd */ + + guint8 dcerpc_ver; /* dcerpc.ver */ + guint8 dcerpc_pkt_type; /* dcerpc.pkt_type */ + guint32 dcerpc_cn_call_id; /* dcerpc.cn_call_id */ + guint16 dcerpc_cn_ctx_id; /* dcerpc.cn_ctx_id */ + + guint16 dns_id; /* dns.id */ + + /* The following values are calculated */ + gboolean pkt_of_interest; + + /* RRPD data for this packet */ + /* Complete this based on the detected protocol */ + RRPD rrpd; + +} PKT_INFO; + +typedef struct _HF_OF_INTEREST +{ + int ip_proto; + int ipv6_nxt; + + int tcp_retran; + int tcp_keep_alive; + int tcp_flags_syn; + int tcp_flags_ack; + int tcp_flags_reset; + int tcp_flags_urg; + int tcp_seq; + int tcp_srcport; + int tcp_dstport; + int tcp_stream; + int tcp_len; + + int udp_srcport; + int udp_dstport; + int udp_stream; + int udp_length; + + int tds_type; + int tds_length; + + int smb_mid; + + int smb2_ses_id; + int smb2_msg_id; + int smb2_cmd; + + int dcerpc_ver; + int dcerpc_pkt_type; + int dcerpc_cn_call_id; + int dcerpc_cn_ctx_id; + + int dns_id; + + int data_data; +} HF_OF_INTEREST; diff --git a/plugins/transum/preferences.h b/plugins/transum/preferences.h new file mode 100644 index 0000000000..4daebbcaf6 --- /dev/null +++ b/plugins/transum/preferences.h @@ -0,0 +1,55 @@ +/* preferences.h +* Header file for the TRANSUM response time analyzer post-dissector +* By Paul Offord +* Copyright 2016 Advance Seven Limited +* +* Wireshark - Network traffic analyzer +* By Gerald Combs +* Copyright 1998 Gerald Combs +* +* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "config.h" +#include +#include + +#define RTE_TIME_SEC 1 +#define RTE_TIME_MSEC 1000 +#define RTE_TIME_USEC 1000000 + +#define TRACE_CAP_CLIENT 1 +#define TRACE_CAP_INTERMEDIATE 2 +#define TRACE_CAP_SERVICE 3 + +/* Add entries to the service port table for packets to be treated as services +* This is populated with preferences "service ports" data */ +typedef struct _TSUM_PREFERENCES +{ + gboolean tsumenabled; + int capture_position; + gboolean reassembly; + guint8 tcp_svc_port[64 * 1024]; + guint8 udp_svc_port[64 * 1024]; + gboolean dcerpc_svc_port[64 * 1024]; + gboolean orphan_ka_discard; + int time_multiplier; + gboolean rte_on_first_req; + gboolean rte_on_last_req; + gboolean rte_on_first_rsp; + gboolean rte_on_last_rsp; + gboolean summarisers_enabled; + gboolean summarise_tds; + gboolean summarisers_escape_quotes; +} TSUM_PREFERENCES;