Sunteți pe pagina 1din 14

WSU03

WSU03: Wireshark Troubleshooting


Network Performance

Appendix C:
Wireshark Code
Wireshark University™

TCP Dissector Code


The following code is from the packet-tcp.c which can be found at
http://anonsvn.wireshark.org/wireshark/trunk/epan/dissectors.

Note: This is only a portion of the code.

/* packet-tcp.c
* Routines for TCP packet disassembly
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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.
*/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdio.h>
#include <string.h>
#include <glib.h>
#include <epan/in_cksum.h>

#include <epan/packet.h>
#include <epan/addr_resolv.h>
#include <epan/ipproto.h>
#include <epan/ip_opts.h>
#include <epan/follow.h>
#include <epan/prefs.h>
#include <epan/emem.h>
#include "packet-tcp.h"
#include "packet-ip.h"
#include "packet-frame.h"
#include <epan/conversation.h>
#include <epan/strutil.h>
#include <epan/reassemble.h>
#include <epan/tap.h>
#include <epan/slab.h>
#include <epan/expert.h>

static int tcp_tap = -1;

/* Place TCP summary in proto tree */


static gboolean tcp_summary_in_tree = TRUE;

/*
* Flag to control whether to check the TCP checksum.
*

WSU03: Troubleshooting Network Performance - Appendix C Page C-2


© 2007 Protocol Analysis Institute, Inc.
Wireshark University™

* In at least some Solaris network traces, there are packets with bad
* TCP checksums, but the traffic appears to indicate that the packets
* *were* received; the packets were probably sent by the host on which
* the capture was being done, on a network interface to which
* checksumming was offloaded, so that DLPI supplied an un-checksummed
* packet to the capture program but a checksummed packet got put onto
* the wire.
*/
static gboolean tcp_check_checksum = TRUE;

extern FILE* data_out_file;

static int proto_tcp = -1;


static int hf_tcp_srcport = -1;
static int hf_tcp_dstport = -1;
static int hf_tcp_port = -1;
static int hf_tcp_seq = -1;
static int hf_tcp_nxtseq = -1;
static int hf_tcp_ack = -1;
static int hf_tcp_hdr_len = -1;
static int hf_tcp_flags = -1;
static int hf_tcp_flags_cwr = -1;
static int hf_tcp_flags_ecn = -1;
static int hf_tcp_flags_urg = -1;
static int hf_tcp_flags_ack = -1;
static int hf_tcp_flags_push = -1;
static int hf_tcp_flags_reset = -1;
static int hf_tcp_flags_syn = -1;
static int hf_tcp_flags_fin = -1;
static int hf_tcp_window_size = -1;
static int hf_tcp_checksum = -1;
static int hf_tcp_checksum_bad = -1;
static int hf_tcp_checksum_good = -1;
static int hf_tcp_len = -1;
static int hf_tcp_urgent_pointer = -1;
static int hf_tcp_analysis_flags = -1;
static int hf_tcp_analysis_acks_frame = -1;
static int hf_tcp_analysis_ack_rtt = -1;
static int hf_tcp_analysis_rto = -1;
static int hf_tcp_analysis_rto_frame = -1;
static int hf_tcp_analysis_retransmission = -1;
static int hf_tcp_analysis_fast_retransmission = -1;
static int hf_tcp_analysis_out_of_order = -1;
static int hf_tcp_analysis_lost_packet = -1;
static int hf_tcp_analysis_ack_lost_packet = -1;
static int hf_tcp_analysis_window_update = -1;
static int hf_tcp_analysis_window_full = -1;
static int hf_tcp_analysis_keep_alive = -1;
static int hf_tcp_analysis_keep_alive_ack = -1;
static int hf_tcp_analysis_duplicate_ack = -1;
static int hf_tcp_analysis_duplicate_ack_num = -1;
static int hf_tcp_analysis_duplicate_ack_frame = -1;
static int hf_tcp_analysis_zero_window = -1;
static int hf_tcp_analysis_zero_window_probe = -1;
static int hf_tcp_analysis_zero_window_probe_ack = -1;
static int hf_tcp_continuation_to = -1;
static int hf_tcp_pdu_time = -1;
static int hf_tcp_pdu_size = -1;
static int hf_tcp_pdu_last_frame = -1;
static int hf_tcp_reassembled_in = -1;
static int hf_tcp_segments = -1;
static int hf_tcp_segment = -1;
static int hf_tcp_segment_overlap = -1;
static int hf_tcp_segment_overlap_conflict = -1;
static int hf_tcp_segment_multiple_tails = -1;
static int hf_tcp_segment_too_long_fragment = -1;
static int hf_tcp_segment_error = -1;
static int hf_tcp_options = -1;
static int hf_tcp_option_mss = -1;
static int hf_tcp_option_mss_val = -1;
static int hf_tcp_option_wscale = -1;

WSU03: Troubleshooting Network Performance - Appendix C Page C-3


© 2007 Protocol Analysis Institute, Inc.
Wireshark University™

static int hf_tcp_option_wscale_val = -1;


static int hf_tcp_option_sack_perm = -1;
static int hf_tcp_option_sack = -1;
static int hf_tcp_option_sack_sle = -1;
static int hf_tcp_option_sack_sre = -1;
static int hf_tcp_option_echo = -1;
static int hf_tcp_option_echo_reply = -1;
static int hf_tcp_option_time_stamp = -1;
static int hf_tcp_option_cc = -1;
static int hf_tcp_option_ccnew = -1;
static int hf_tcp_option_ccecho = -1;
static int hf_tcp_option_md5 = -1;

static gint ett_tcp = -1;


static gint ett_tcp_flags = -1;
static gint ett_tcp_options = -1;
static gint ett_tcp_option_sack = -1;
static gint ett_tcp_analysis = -1;
static gint ett_tcp_analysis_faults = -1;
static gint ett_tcp_segments = -1;
static gint ett_tcp_segment = -1;
static gint ett_tcp_checksum = -1;

/* not all of the hf_fields below make sense for TCP but we have to provide
them anyways to comply with the api (which was aimed for ip fragment
reassembly) */
static const fragment_items tcp_segment_items = {
&ett_tcp_segment,
&ett_tcp_segments,
&hf_tcp_segments,
&hf_tcp_segment,
&hf_tcp_segment_overlap,
&hf_tcp_segment_overlap_conflict,
&hf_tcp_segment_multiple_tails,
&hf_tcp_segment_too_long_fragment,
&hf_tcp_segment_error,
&hf_tcp_reassembled_in,
"Segments"
};

static dissector_table_t subdissector_table;


static heur_dissector_list_t heur_subdissector_list;
static dissector_handle_t data_handle;

/* TCP structs and definitions */

/* **************************************************************************

* RTT and reltive sequence numbers.


* **************************************************************************/
static gboolean tcp_analyze_seq = TRUE;
static gboolean tcp_relative_seq = TRUE;

/* SLAB allocator for tcp_unacked structures


*/
SLAB_ITEM_TYPE_DEFINE(tcp_unacked_t)
static SLAB_FREE_LIST_DEFINE(tcp_unacked_t)
#define TCP_UNACKED_NEW(fi) \
SLAB_ALLOC(fi, tcp_unacked_t)
#define TCP_UNACKED_FREE(fi) \
SLAB_FREE(fi, tcp_unacked_t)

/* Idea for gt: either x > y, or y is much bigger (assume wrap) */


#define GT_SEQ(x, y) ((gint32)((y) - (x)) < 0)
#define LT_SEQ(x, y) ((gint32)((x) - (y)) < 0)
#define GE_SEQ(x, y) ((gint32)((y) - (x)) <= 0)
#define LE_SEQ(x, y) ((gint32)((x) - (y)) <= 0)
#define EQ_SEQ(x, y) ((x) == (y))

WSU03: Troubleshooting Network Performance - Appendix C Page C-4


© 2007 Protocol Analysis Institute, Inc.
Wireshark University™

#define TCP_A_RETRANSMISSION 0x0001


#define TCP_A_LOST_PACKET 0x0002
#define TCP_A_ACK_LOST_PACKET 0x0004
#define TCP_A_KEEP_ALIVE 0x0008
#define TCP_A_DUPLICATE_ACK 0x0010
#define TCP_A_ZERO_WINDOW 0x0020
#define TCP_A_ZERO_WINDOW_PROBE 0x0040
#define TCP_A_ZERO_WINDOW_PROBE_ACK 0x0080
#define TCP_A_KEEP_ALIVE_ACK 0x0100
#define TCP_A_OUT_OF_ORDER 0x0200
#define TCP_A_FAST_RETRANSMISSION 0x0400
#define TCP_A_WINDOW_UPDATE 0x0800
#define TCP_A_WINDOW_FULL 0x1000

static void
process_tcp_payload(tvbuff_t *tvb, volatile int offset, packet_info *pinfo,
proto_tree *tree, proto_tree *tcp_tree, int src_port, int dst_port,
guint32 seq, guint32 nxtseq, gboolean is_tcp_segment,
struct tcp_analysis *tcpd);

struct tcp_analysis *
get_tcp_conversation_data(packet_info *pinfo)
{
int direction;
conversation_t *conv=NULL;
struct tcp_analysis *tcpd=NULL;

/* Have we seen this conversation before? */


if( (conv=find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo-
>ptype, pinfo->srcport, pinfo->destport, 0)) == NULL){
/* No this is a new conversation. */
conv=conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo-
>ptype, pinfo->srcport, pinfo->destport, 0);
}

/* check if we have any data for this conversation */


tcpd=conversation_get_proto_data(conv, proto_tcp);
if(!tcpd){
/* No no such data yet. Allocate and init it */
tcpd=se_alloc(sizeof(struct tcp_analysis));
tcpd->flow1.segments=NULL;
tcpd->flow1.base_seq=0;
tcpd->flow1.lastack=0;
tcpd->flow1.lastacktime.secs=0;
tcpd->flow1.lastacktime.nsecs=0;
tcpd->flow1.lastnondupack=0;
tcpd->flow1.nextseq=0;
tcpd->flow1.nextseqtime.secs=0;
tcpd->flow1.nextseqtime.nsecs=0;
tcpd->flow1.nextseqframe=0;
tcpd->flow1.window=0;
tcpd->flow1.win_scale=-1;
tcpd->flow1.flags=0;
tcpd-
>flow1.multisegment_pdus=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK,
"tcp_multisegment_pdus");
tcpd->flow2.segments=NULL;
tcpd->flow2.base_seq=0;
tcpd->flow2.lastack=0;
tcpd->flow2.lastacktime.secs=0;
tcpd->flow2.lastacktime.nsecs=0;
tcpd->flow2.lastnondupack=0;
tcpd->flow2.nextseq=0;
tcpd->flow2.nextseqtime.secs=0;
tcpd->flow2.nextseqtime.nsecs=0;
tcpd->flow2.nextseqframe=0;
tcpd->flow2.window=0;
tcpd->flow2.win_scale=-1;
tcpd->flow2.flags=0;

WSU03: Troubleshooting Network Performance - Appendix C Page C-5


© 2007 Protocol Analysis Institute, Inc.
Wireshark University™

tcpd-
>flow2.multisegment_pdus=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK,
"tcp_multisegment_pdus");
tcpd-
>acked_table=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK,
"tcp_analyze_acked_table");

conversation_add_proto_data(conv, proto_tcp, tcpd);


}

/* check direction and get ua lists */


direction=CMP_ADDRESS(&pinfo->src, &pinfo->dst);
/* if the addresses are equal, match the ports instead */
if(direction==0) {
direction= (pinfo->srcport > pinfo->destport)*2-1;
}
if(direction>=0){
tcpd->fwd=&(tcpd->flow1);
tcpd->rev=&(tcpd->flow2);
} else {
tcpd->fwd=&(tcpd->flow2);
tcpd->rev=&(tcpd->flow1);
}

tcpd->ta=NULL;
return tcpd;
}

static void
print_pdu_tracking_data(packet_info *pinfo, tvbuff_t *tvb, proto_tree *tcp_tree, struct
tcp_multisegment_pdu *msp)
{
proto_item *item;

if (check_col(pinfo->cinfo, COL_INFO)){
col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, "[Continuation to #%u]
", msp->first_frame);
}
item=proto_tree_add_uint(tcp_tree, hf_tcp_continuation_to,
tvb, 0, 0, msp->first_frame);
PROTO_ITEM_SET_GENERATED(item);
}

/* if we know that a PDU starts inside this segment, return the adjusted
offset to where that PDU starts or just return offset back
and let TCP try to find out what it can about this segment
*/
static int
scan_for_next_pdu(tvbuff_t *tvb, proto_tree *tcp_tree, packet_info *pinfo, int offset,
guint32 seq, guint32 nxtseq, struct tcp_analysis *tcpd)
{
struct tcp_multisegment_pdu *msp=NULL;

if(!pinfo->fd->flags.visited){
msp=se_tree_lookup32_le(tcpd->fwd->multisegment_pdus, seq-1);
if(msp){
/* If this is a continuation of a PDU started in a
* previous segment we need to update the last_frame
* variables.
*/
if(seq>msp->seq && seq<msp->nxtpdu){
msp->last_frame=pinfo->fd->num;
msp->last_frame_time=pinfo->fd->abs_ts;
print_pdu_tracking_data(pinfo, tvb, tcp_tree, msp);
}

/* If this segment is completely within a previous PDU


* then we just skip this packet
*/

WSU03: Troubleshooting Network Performance - Appendix C Page C-6


© 2007 Protocol Analysis Institute, Inc.
Wireshark University™

if(seq>msp->seq && nxtseq<=msp->nxtpdu){


return -1;
}
if(seq<msp->nxtpdu && nxtseq>msp->nxtpdu){
offset+=msp->nxtpdu-seq;
return offset;
}

}
} else {
/* First we try to find the start and transfer time for a PDU.
* We only print this for the very first segment of a PDU
* and only for PDUs spanning multiple segments.
* Se we look for if there was any multisegment PDU started
* just BEFORE the end of this segment. I.e. either inside this
* segment or in a previous segment.
* Since this might also match PDUs that are completely within
* this segment we also verify that the found PDU does span
* beyond the end of this segment.
*/
msp=se_tree_lookup32_le(tcpd->fwd->multisegment_pdus, nxtseq-1);
if(msp){
if( (pinfo->fd->num==msp->first_frame)
){
proto_item *item;
nstime_t ns;

item=proto_tree_add_uint(tcp_tree,
hf_tcp_pdu_last_frame, tvb, 0, 0, msp->last_frame);
PROTO_ITEM_SET_GENERATED(item);

nstime_delta(&ns, &msp->last_frame_time, &pinfo-


>fd->abs_ts);
item = proto_tree_add_time(tcp_tree,
hf_tcp_pdu_time,
tvb, 0, 0, &ns);
PROTO_ITEM_SET_GENERATED(item);
}
}

/* Second we check if this segment is part of a PDU started


* prior to the segment (seq-1)
*/
msp=se_tree_lookup32_le(tcpd->fwd->multisegment_pdus, seq-1);
if(msp){
/* If this segment is completely within a previous PDU
* then we just skip this packet
*/
if(seq>msp->seq && nxtseq<=msp->nxtpdu){
print_pdu_tracking_data(pinfo, tvb, tcp_tree, msp);
return -1;
}

if(seq<msp->nxtpdu && nxtseq>msp->nxtpdu){


offset+=msp->nxtpdu-seq;
return offset;
}
}

}
return offset;
}

/* if we saw a PDU that extended beyond the end of the segment,


use this function to remember where the next pdu starts
*/
static struct tcp_multisegment_pdu *
pdu_store_sequencenumber_of_next_pdu(packet_info *pinfo, guint32 seq, guint32 nxtpdu,
struct tcp_analysis *tcpd)
{
struct tcp_multisegment_pdu *msp;

WSU03: Troubleshooting Network Performance - Appendix C Page C-7


© 2007 Protocol Analysis Institute, Inc.
Wireshark University™

msp=se_alloc(sizeof(struct tcp_multisegment_pdu));
msp->nxtpdu=nxtpdu;
msp->seq=seq;
msp->first_frame=pinfo->fd->num;
msp->last_frame=pinfo->fd->num;
msp->last_frame_time=pinfo->fd->abs_ts;
msp->flags=0;
se_tree_insert32(tcpd->fwd->multisegment_pdus, seq, (void *)msp);
return msp;
}

/* This is called for SYN+ACK packets and the purpose is to verify that we
* have seen window scaling in both directions.
* If we cant find window scaling being set in both directions
* that means it was present in the SYN but not in the SYN+ACK
* (or the SYN was missing) and then we disable the window scaling
* for this tcp session.
*/
static void
verify_tcp_window_scaling(struct tcp_analysis *tcpd)
{
if( tcpd && ((tcpd->flow1.win_scale==-1) || (tcpd->flow2.win_scale==-1)) ){
tcpd->flow1.win_scale=-1;
tcpd->flow2.win_scale=-1;
}
}

/* if we saw a window scaling option, store it for future reference


*/
static void
pdu_store_window_scale_option(guint8 ws, struct tcp_analysis *tcpd)
{
tcpd->fwd->win_scale=ws;
}

static void
tcp_get_relative_seq_ack(guint32 *seq, guint32 *ack, guint32 *win, struct tcp_analysis
*tcpd)
{
if(tcp_relative_seq){
(*seq) -= tcpd->fwd->base_seq;
(*ack) -= tcpd->rev->base_seq;
if(tcpd->fwd->win_scale!=-1){
(*win)<<=tcpd->fwd->win_scale;
}
}
}

/* when this function returns, it will (if createflag) populate the ta pointer.
*/
static void
tcp_analyze_get_acked_struct(guint32 frame, gboolean createflag, struct tcp_analysis
*tcpd)
{
tcpd->ta=se_tree_lookup32(tcpd->acked_table, frame);
if((!tcpd->ta) && createflag){
tcpd->ta=se_alloc(sizeof(struct tcp_acked));
tcpd->ta->frame_acked=0;
tcpd->ta->ts.secs=0;
tcpd->ta->ts.nsecs=0;
tcpd->ta->flags=0;
tcpd->ta->dupack_num=0;
tcpd->ta->dupack_frame=0;
se_tree_insert32(tcpd->acked_table, frame, (void *)tcpd->ta);
}
}

/* fwd contains a list of all segments processed but not yet ACKed in the

WSU03: Troubleshooting Network Performance - Appendix C Page C-8


© 2007 Protocol Analysis Institute, Inc.
Wireshark University™

* same direction as the current segment.


* rev contains a list of all segments received but not yet ACKed in the
* opposite direction to the current segment.
*
* New segments are always added to the head of the fwd/rev lists.
*
*/
static void
tcp_analyze_sequence_number(packet_info *pinfo, guint32 seq, guint32 ack, guint32 seglen,
guint8 flags, guint32 window, struct tcp_analysis *tcpd)
{
tcp_unacked_t *ual=NULL;
int ackcount;

#ifdef REMOVED
printf("analyze_sequence numbers frame:%d direction:%s\n",pinfo->fd-
>num,direction>=0?"FWD":"REW");
printf("FWD list lastflags:0x%04x base_seq:0x%08x:\n",tcpd->fwd->lastsegmentflags,tcpd-
>fwd->base_seq);for(ual=tcpd->fwd->segments;ual;ual=ual->next)printf("Frame:%d Seq:%d
Nextseq:%d\n",ual->frame,ual->seq,ual->nextseq);
printf("REV list lastflags:0x%04x base_seq:0x%08x:\n",tcpd->rev->lastsegmentflags,tcpd-
>rev->base_seq);for(ual=tcpd->rev->segments;ual;ual=ual->next)printf("Frame:%d Seq:%d
Nextseq:%d\n",ual->frame,ual->seq,ual->nextseq);
#endif

/* if this is the first segment for this list we need to store the
* base_seq
*/
if(tcpd->fwd->base_seq==0){
tcpd->fwd->base_seq=seq;
}
/* if we have spotted a new base_Seq in the reverse direction
* store it.
*/
if(tcpd->rev->base_seq==0){
tcpd->rev->base_seq=ack;
}

/* ZERO WINDOW PROBE


* it is a zero window probe if
* the sequnece number is the next expected one
* the window in the other direction is 0
* the segment is exactly 1 byte
*/
/*QQQ tested*/
if( seglen==1
&& seq==tcpd->fwd->nextseq
&& tcpd->rev->window==0 ){
if(!tcpd->ta){
tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd);
}
tcpd->ta->flags|=TCP_A_ZERO_WINDOW_PROBE;
goto finished_fwd;
}

/* ZERO WINDOW
* a zero window packet has window == 0 but none of the SYN/FIN/RST set
*/
/*QQQ tested*/
if( window==0
&& (flags&(TH_RST|TH_FIN|TH_SYN))==0 ){
if(!tcpd->ta){
tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd);
}
tcpd->ta->flags|=TCP_A_ZERO_WINDOW;
}

WSU03: Troubleshooting Network Performance - Appendix C Page C-9


© 2007 Protocol Analysis Institute, Inc.
Wireshark University™

/* LOST PACKET
* If this segment is beyond the last seen nextseq we must
* have missed some previous segment
*
* We only check for this if we have actually seen segments prior to this
* one.
* RST packets are not checked for this.
*/
if( tcpd->fwd->nextseq
&& GT_SEQ(seq, tcpd->fwd->nextseq)
&& (flags&(TH_RST))==0 ){
if(!tcpd->ta){
tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd);
}
tcpd->ta->flags|=TCP_A_LOST_PACKET;
}

/* KEEP ALIVE
* a keepalive contains 0 or 1 bytes of data and starts one byte prior
* to what should be the next sequence number.
* SYN/FIN/RST segments are never keepalives
*/
/*QQQ tested */
if( (seglen==0||seglen==1)
&& seq==(tcpd->fwd->nextseq-1)
&& (flags&(TH_SYN|TH_FIN|TH_RST))==0 ){
if(!tcpd->ta){
tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd);
}
tcpd->ta->flags|=TCP_A_KEEP_ALIVE;
}

/* WINDOW UPDATE
* A window update is a 0 byte segment with the same SEQ/ACK numbers as
* the previous seen segment and with a new window value
*/
if( seglen==0
&& window
&& window!=tcpd->fwd->window
&& seq==tcpd->fwd->nextseq
&& ack==tcpd->fwd->lastack
&& (flags&(TH_SYN|TH_FIN|TH_RST))==0 ){
if(!tcpd->ta){
tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd);
}
tcpd->ta->flags|=TCP_A_WINDOW_UPDATE;
}

/* WINDOW FULL
* If we know the window scaling
* and if this segment contains data ang goes all the way to the
* edge of the advertized window
* then we mark it as WINDOW FULL
* SYN/RST/FIN packets are never WINDOW FULL
*/
/*QQQ tested*/
if( seglen>0
&& tcpd->fwd->win_scale!=-1
&& tcpd->rev->win_scale!=-1
&& (seq+seglen)==(tcpd->rev->lastack+(tcpd->rev->window<<tcpd->rev->win_scale))
&& (flags&(TH_SYN|TH_FIN|TH_RST))==0 ){
if(!tcpd->ta){
tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd);

WSU03: Troubleshooting Network Performance - Appendix C Page C-10


© 2007 Protocol Analysis Institute, Inc.
Wireshark University™

}
tcpd->ta->flags|=TCP_A_WINDOW_FULL;
}

/* KEEP ALIVE ACK


* It is a keepalive ack if it repeats the previous ACK and if
* the last segment in the reverse direction was a keepalive
*/
/*QQQ tested*/
if( seglen==0
&& window
&& window==tcpd->fwd->window
&& seq==tcpd->fwd->nextseq
&& ack==tcpd->fwd->lastack
&& (tcpd->rev->lastsegmentflags&TCP_A_KEEP_ALIVE)
&& (flags&(TH_SYN|TH_FIN|TH_RST))==0 ){
if(!tcpd->ta){
tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd);
}
tcpd->ta->flags|=TCP_A_KEEP_ALIVE_ACK;
goto finished_fwd;
}

/* ZERO WINDOW PROBE ACK


* It is a zerowindowprobe ack if it repeats the previous ACK and if
* the last segment in the reverse direction was a zerowindowprobe
* It also repeats the previous zero window indication
*/
/*QQQ tested*/
if( seglen==0
&& window==0
&& window==tcpd->fwd->window
&& seq==tcpd->fwd->nextseq
&& ack==tcpd->fwd->lastack
&& (tcpd->rev->lastsegmentflags&TCP_A_ZERO_WINDOW_PROBE)
&& (flags&(TH_SYN|TH_FIN|TH_RST))==0 ){
if(!tcpd->ta){
tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd);
}
tcpd->ta->flags|=TCP_A_ZERO_WINDOW_PROBE_ACK;
goto finished_fwd;
}

/* DUPLICATE ACK
* It is a duplicate ack if window/seq/ack is the same as the previous
* segment and if the segment length is 0
*/
if( seglen==0
&& window
&& window==tcpd->fwd->window
&& seq==tcpd->fwd->nextseq
&& ack==tcpd->fwd->lastack
&& (flags&(TH_SYN|TH_FIN|TH_RST))==0 ){
tcpd->fwd->dupacknum++;
if(!tcpd->ta){
tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd);
}
tcpd->ta->flags|=TCP_A_DUPLICATE_ACK;
tcpd->ta->dupack_num=tcpd->fwd->dupacknum;
tcpd->ta->dupack_frame=tcpd->fwd->lastnondupack;
}

finished_fwd:
/* If this was NOT a dupack we must reset the dupack counters */
if( (!tcpd->ta) || !(tcpd->ta->flags&TCP_A_DUPLICATE_ACK) ){

WSU03: Troubleshooting Network Performance - Appendix C Page C-11


© 2007 Protocol Analysis Institute, Inc.
Wireshark University™

tcpd->fwd->lastnondupack=pinfo->fd->num;
tcpd->fwd->dupacknum=0;
}

/* ACKED LOST PACKET


* If this segment acks beyond the nextseqnum in the other direction
* then that means we have missed packets going in the
* other direction
*
* We only check this if we have actually seen some seq numbers
* in the other direction.
*/
if( tcpd->rev->nextseq
&& GT_SEQ(ack, tcpd->rev->nextseq )
&& (flags&(TH_ACK))!=0 ){
/*QQQ tested*/
if(!tcpd->ta){
tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd);
}
tcpd->ta->flags|=TCP_A_ACK_LOST_PACKET;
/* update nextseq in the other direction so we dont get
* this indication again.
*/
tcpd->rev->nextseq=ack;
}

/* RETRANSMISSION/FAST RETRANSMISSION/OUT-OF-ORDER
* If the segments contains data and if it does not advance
* sequence number it must be either of these three.
* Only test for this if we know what the seq number should be
* (tcpd->fwd->nextseq)
*
* Note that a simple KeepAlive is not a retransmission
*/
if( seglen>0
&& tcpd->fwd->nextseq
&& (LT_SEQ(seq, tcpd->fwd->nextseq)) ){
guint32 t;

if(tcpd->ta && (tcpd->ta->flags&TCP_A_KEEP_ALIVE) ){


goto finished_checking_retransmission_type;
}

/* If there were >=2 duplicate ACKs in the reverse direction


* (there might be duplicate acks missing from the trace)
* and if this sequence number matches those ACKs
* and if the packet occurs within 20ms of the last
* duplicate ack
* then this is a fast retransmission
*/
t=(pinfo->fd->abs_ts.secs-tcpd->rev->lastacktime.secs)*1000000000;
t=t+(pinfo->fd->abs_ts.nsecs)-tcpd->rev->lastacktime.nsecs;
if( tcpd->rev->dupacknum>=2
&& tcpd->rev->lastack==seq
&& t<20000000 ){
if(!tcpd->ta){
tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE,
tcpd);
}
tcpd->ta->flags|=TCP_A_FAST_RETRANSMISSION;
goto finished_checking_retransmission_type;
}

/* If the segment came <3ms since the segment with the highest
* seen sequence number, then it is an OUT-OF-ORDER segment.
* (3ms is an arbitrary number)
*/
t=(pinfo->fd->abs_ts.secs-tcpd->fwd->nextseqtime.secs)*1000000000;

WSU03: Troubleshooting Network Performance - Appendix C Page C-12


© 2007 Protocol Analysis Institute, Inc.
Wireshark University™

t=t+(pinfo->fd->abs_ts.nsecs)-tcpd->fwd->nextseqtime.nsecs;
if( t<3000000 ){
if(!tcpd->ta){
tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE,
tcpd);
}
tcpd->ta->flags|=TCP_A_OUT_OF_ORDER;
goto finished_checking_retransmission_type;
}

/* Then it has to be a generic retransmission */


if(!tcpd->ta){
tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd);
}
tcpd->ta->flags|=TCP_A_RETRANSMISSION;
nstime_delta(&tcpd->ta->rto_ts, &pinfo->fd->abs_ts, &tcpd->fwd-
>nextseqtime);
tcpd->ta->rto_frame=tcpd->fwd->nextseqframe;
}
finished_checking_retransmission_type:

/* add this new sequence number to the fwd list */


TCP_UNACKED_NEW(ual);
ual->next=tcpd->fwd->segments;
tcpd->fwd->segments=ual;
ual->frame=pinfo->fd->num;
ual->seq=seq;
ual->ts=pinfo->fd->abs_ts;

/* next sequence number is seglen bytes away, plus SYN/FIN which counts as one
byte */
ual->nextseq=seq+seglen;
if( flags&(TH_SYN|TH_FIN) ){
ual->nextseq+=1;
}

/* Store the highest number seen so far for nextseq so we can detect
* when we receive segments that arrive with a "hole"
* If we dont have anything since before, just store what we got.
* ZeroWindowProbes are special and dont really advance the nextseq
*/
if(GT_SEQ(ual->nextseq, tcpd->fwd->nextseq) || !tcpd->fwd->nextseq) {
if( !tcpd->ta || !(tcpd->ta->flags&TCP_A_ZERO_WINDOW_PROBE) ){
tcpd->fwd->nextseq=ual->nextseq;
tcpd->fwd->nextseqframe=pinfo->fd->num;
tcpd->fwd->nextseqtime.secs=pinfo->fd->abs_ts.secs;
tcpd->fwd->nextseqtime.nsecs=pinfo->fd->abs_ts.nsecs;
}
}

/* remember what the ack/window is so we can track window updates and


retransmissions */
tcpd->fwd->window=window;
tcpd->fwd->lastack=ack;
tcpd->fwd->lastacktime.secs=pinfo->fd->abs_ts.secs;
tcpd->fwd->lastacktime.nsecs=pinfo->fd->abs_ts.nsecs;

/* if there were any flags set for this segment we need to remember them
* we only remember the flags for the very last segment though.
*/
if(tcpd->ta){
tcpd->fwd->lastsegmentflags=tcpd->ta->flags;
} else {
tcpd->fwd->lastsegmentflags=0;
}

/* remove all segments this ACKs and we dont need to keep around any more

WSU03: Troubleshooting Network Performance - Appendix C Page C-13


© 2007 Protocol Analysis Institute, Inc.
Wireshark University™

*/
ackcount=0;
/* first we remove all such segments at the head of the list */
while((ual=tcpd->rev->segments)){
tcp_unacked_t *tmpual;
if(ack==ual->nextseq){
tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd);
tcpd->ta->frame_acked=ual->frame;
nstime_delta(&tcpd->ta->ts, &pinfo->fd->abs_ts, &ual->ts);
}
if(GT_SEQ(ual->nextseq,ack)){
break;
}
if(!ackcount){
/*qqq do the ACKs segment x delta y */
}
ackcount++;
tmpual=tcpd->rev->segments->next;
TCP_UNACKED_FREE(ual);
tcpd->rev->segments=tmpual;
}
/* now we remove all such segments that are NOT at the head of the list */
ual=tcpd->rev->segments;
while(ual && ual->next){
tcp_unacked_t *tmpual;
if(GT_SEQ(ual->next->nextseq,ack)){
ual=ual->next;
continue;
}
if(!ackcount){
/*qqq do the ACKs segment x delta y */
}
ackcount++;
tmpual=ual->next->next;
TCP_UNACKED_FREE(ual->next);
ual->next=tmpual;
ual=ual->next;
}

Note: This is only a portion of the code.

WSU03: Troubleshooting Network Performance - Appendix C Page C-14


© 2007 Protocol Analysis Institute, Inc.

S-ar putea să vă placă și