Wireshark-dev: [Wireshark-dev] [Patch, RFC] to TCP Sequence Analysis
From: Martin Mathieson <martin.r.mathieson@xxxxxxxxxxxxxx>
Date: Sat, 24 Mar 2012 01:11:53 +0000
Hi,
I'm now needing to analyse TCP conversations carried over LTE MAC/RLC/PDCP/IP. So one frame in a log or capture can hold many segments of the same TCP conversation.
The current implementation for TCP analysis is that there is a tcp_analysis struct for each conversation.
Within that struct there is a map (emem_tree_t) from frame number -> tcp_acked
The tcp_acked struct holds the result of the analysis done on a segment during the first pass through the segments of the TCP conversation.
When a frame is re-dissected, we look up the appropriate tcp_acked struct for the segment and apply its findings to the segment currently being dissected. The problem for me is that I often have several segments with the same frame number, so they all get tagged with the same (last?) analysis stored in a single tcp_acked struct.
My change was to expand the key now to include frame+sequence-number+ack-number (where the sequence-number and ack-number are the raw, rather than relative, values), which works well for me.
Is there a more appropriate key for looking up the segment? I did think about adding an index for the segment within the frame, but that would be messy, and if you had to segments with the same seq+ack, I think the same analysis would always apply.
I know that the TCP analysis functionality gets used a lot, so I'm very wary of breaking it. At the very least this will slow it down a little and use more memory. But I surely can't be the only person who has this problem...
Thanks,
Martin
Index: packet-tcp.c =================================================================== --- packet-tcp.c (revision 41749) +++ packet-tcp.c (working copy) @@ -94,6 +94,7 @@ 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 = -1; static int hf_tcp_analysis_flags = -1; static int hf_tcp_analysis_bytes_in_flight = -1; static int hf_tcp_analysis_acks_frame = -1; @@ -753,15 +754,28 @@ /* 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) +tcp_analyze_get_acked_struct(guint32 frame, guint32 seq, guint32 ack, gboolean createflag, struct tcp_analysis *tcpd) { - if (!tcpd) + emem_tree_key_t keys[2]; + guint32 values[3]; + + if (!tcpd) { return; + } - tcpd->ta=se_tree_lookup32(tcpd->acked_table, frame); + /* Get key ready */ + keys[0].length = 3; + keys[0].key = values; + values[0] = frame; + values[1] = seq; + values[2] = ack; + keys[1].length = 0; + keys[1].key = NULL; + + tcpd->ta = se_tree_lookup32_array(tcpd->acked_table, keys); if((!tcpd->ta) && createflag){ - tcpd->ta=se_alloc0(sizeof(struct tcp_acked)); - se_tree_insert32(tcpd->acked_table, frame, (void *)tcpd->ta); + tcpd->ta = se_alloc0(sizeof(struct tcp_acked)); + se_tree_insert32_array(tcpd->acked_table, keys, (void *)tcpd->ta); } } @@ -829,7 +843,7 @@ && seq==tcpd->fwd->nextseq && tcpd->rev->window==0 ){ if(!tcpd->ta){ - tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, TRUE, tcpd); } tcpd->ta->flags|=TCP_A_ZERO_WINDOW_PROBE; goto finished_fwd; @@ -843,7 +857,7 @@ if( window==0 && (flags&(TH_RST|TH_FIN|TH_SYN))==0 ){ if(!tcpd->ta){ - tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, TRUE, tcpd); } tcpd->ta->flags|=TCP_A_ZERO_WINDOW; } @@ -861,7 +875,7 @@ && GT_SEQ(seq, tcpd->fwd->nextseq) && (flags&(TH_RST))==0 ){ if(!tcpd->ta){ - tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, TRUE, tcpd); } tcpd->ta->flags|=TCP_A_LOST_PACKET; @@ -880,7 +894,7 @@ && 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); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, TRUE, tcpd); } tcpd->ta->flags|=TCP_A_KEEP_ALIVE; } @@ -896,7 +910,7 @@ && 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); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, TRUE, tcpd); } tcpd->ta->flags|=TCP_A_WINDOW_UPDATE; } @@ -915,7 +929,7 @@ && (seq+seglen)==(tcpd->rev->lastack+(tcpd->rev->window<<(tcpd->rev->win_scale==-2?0: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); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, TRUE, tcpd); } tcpd->ta->flags|=TCP_A_WINDOW_FULL; } @@ -934,7 +948,7 @@ && (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); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, TRUE, tcpd); } tcpd->ta->flags|=TCP_A_KEEP_ALIVE_ACK; goto finished_fwd; @@ -955,7 +969,7 @@ && (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); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, TRUE, tcpd); } tcpd->ta->flags|=TCP_A_ZERO_WINDOW_PROBE_ACK; goto finished_fwd; @@ -974,7 +988,7 @@ && (flags&(TH_SYN|TH_FIN|TH_RST))==0 ){ tcpd->fwd->dupacknum++; if(!tcpd->ta){ - tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, TRUE, tcpd); } tcpd->ta->flags|=TCP_A_DUPLICATE_ACK; tcpd->ta->dupack_num=tcpd->fwd->dupacknum; @@ -1004,7 +1018,7 @@ && (flags&(TH_ACK))!=0 ){ /*QQQ tested*/ if(!tcpd->ta){ - tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, TRUE, tcpd); } tcpd->ta->flags|=TCP_A_ACK_LOST_PACKET; /* update 'max seq to be acked' in the other direction so we don't get @@ -1044,7 +1058,7 @@ && tcpd->rev->lastack==seq && t<20000000 ){ if(!tcpd->ta){ - tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, TRUE, tcpd); } tcpd->ta->flags|=TCP_A_FAST_RETRANSMISSION; goto finished_checking_retransmission_type; @@ -1060,7 +1074,7 @@ if( t<3000000 && tcpd->fwd->nextseq != seq + seglen ){ if(!tcpd->ta){ - tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, TRUE, tcpd); } tcpd->ta->flags|=TCP_A_OUT_OF_ORDER; goto finished_checking_retransmission_type; @@ -1068,7 +1082,7 @@ /* Then it has to be a generic retransmission */ if(!tcpd->ta){ - tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, TRUE, tcpd); } tcpd->ta->flags|=TCP_A_RETRANSMISSION; nstime_delta(&tcpd->ta->rto_ts, &pinfo->fd->abs_ts, &tcpd->fwd->nextseqtime); @@ -1145,7 +1159,7 @@ /* If this ack matches the segment, process accordingly */ if(ack==ual->nextseq){ - tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, TRUE, tcpd); tcpd->ta->frame_acked=ual->frame; nstime_delta(&tcpd->ta->ts, &pinfo->fd->abs_ts, &ual->ts); } @@ -1206,7 +1220,7 @@ if (in_flight>0 && in_flight<2000000000) { if(!tcpd->ta){ - tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, TRUE, tcpd); } tcpd->ta->bytes_in_flight = in_flight; } @@ -1536,7 +1550,8 @@ } static void -tcp_print_sequence_number_analysis(packet_info *pinfo, tvbuff_t *tvb, proto_tree *parent_tree, struct tcp_analysis *tcpd) +tcp_print_sequence_number_analysis(packet_info *pinfo, tvbuff_t *tvb, proto_tree *parent_tree, + struct tcp_analysis *tcpd, guint32 seq, guint32 ack) { struct tcp_acked *ta = NULL; proto_item *item; @@ -1547,14 +1562,14 @@ return; } if(!tcpd->ta){ - tcp_analyze_get_acked_struct(pinfo->fd->num, FALSE, tcpd); + tcp_analyze_get_acked_struct(pinfo->fd->num, seq, ack, FALSE, tcpd); } ta=tcpd->ta; if(!ta){ return; } - item=proto_tree_add_text(parent_tree, tvb, 0, 0, "SEQ/ACK analysis"); + item=proto_tree_add_item(parent_tree, hf_tcp_analysis, tvb, 0, 0, ENC_NA); PROTO_ITEM_SET_GENERATED(item); tree=proto_item_add_subtree(item, ett_tcp_analysis); @@ -4096,7 +4111,7 @@ tcpd=get_tcp_conversation_data(conv,pinfo); } if(!tcpd->ta) - tcp_analyze_get_acked_struct(pinfo->fd->num, TRUE, tcpd); + tcp_analyze_get_acked_struct(pinfo->fd->num, tcph->th_seq, tcph->th_ack, TRUE, tcpd); tcpd->ta->flags|=TCP_A_REUSED_PORTS; } @@ -4587,7 +4602,14 @@ /* handle TCP seq# analysis, print any extra SEQ/ACK data for this segment*/ if(tcp_analyze_seq){ - tcp_print_sequence_number_analysis(pinfo, tvb, tcp_tree, tcpd); + guint32 use_seq = tcph->th_seq; + guint32 use_ack = tcph->th_ack; + /* May need to recover absolute values here... */ + if (tcp_relative_seq) { + use_seq += tcpd->fwd->base_seq; + use_ack += tcpd->rev->base_seq; + } + tcp_print_sequence_number_analysis(pinfo, tvb, tcp_tree, tcpd, use_seq, use_ack); } /* handle conversation timestamps */ @@ -4813,6 +4835,10 @@ { "Bad Checksum", "tcp.checksum_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "True: checksum doesn't match packet content; False: matches content or not checked", HFILL }}, + { &hf_tcp_analysis, + { "SEQ/ACK analysis", "tcp.analysis", FT_NONE, BASE_NONE, NULL, 0x0, + "This frame has some of the TCP analysis shown", HFILL }}, + { &hf_tcp_analysis_flags, { "TCP Analysis Flags", "tcp.analysis.flags", FT_NONE, BASE_NONE, NULL, 0x0, "This frame has some of the TCP analysis flags set", HFILL }},
- Follow-Ups:
- Re: [Wireshark-dev] [Patch, RFC] to TCP Sequence Analysis
- From: Guy Harris
- Re: [Wireshark-dev] [Patch, RFC] to TCP Sequence Analysis
- Prev by Date: [Wireshark-dev] Windows-7-x64 buildbot stuck
- Next by Date: Re: [Wireshark-dev] [Patch, RFC] to TCP Sequence Analysis
- Previous by thread: [Wireshark-dev] Windows-7-x64 buildbot stuck
- Next by thread: Re: [Wireshark-dev] [Patch, RFC] to TCP Sequence Analysis
- Index(es):