TCP: Add support for TCP Conversation Completeness tracking
TCP Conversations are modified to track Completeness, particularly initial and closing handshakes Fixes #16716
This commit is contained in:
parent
0a3eba683d
commit
2f235deb3e
|
@ -31,6 +31,9 @@ See the “New and Updated Features” section below for more details.
|
|||
|
||||
The following features are new (or have been significantly updated) since version 3.4.0:
|
||||
|
||||
* TCP conversations now support a completeness criteria, which facilitates the identification of TCP streams having any
|
||||
of opening or closing handshakes, a payload, in any combination. It is accessed with the new tcp.completeness filter.
|
||||
|
||||
* Protobuf fields that are not serialized on the wire (missing in capture files) can now be displayed with default values
|
||||
by setting the new 'add_default_value' preference. The default values might be explicitly declared in 'proto2' files,
|
||||
or false for bools, first value for enums, zero for numeric types.
|
||||
|
|
|
@ -608,6 +608,28 @@ Set when the all of the following are true:
|
|||
|
||||
Supersedes “TCP Dup ACK”.
|
||||
|
||||
// TCP_A_CONVERSATION_COMPLETENESS
|
||||
[discrete]
|
||||
==== TCP Conversation Completeness
|
||||
|
||||
TCP conversations are said to be complete when they have both opening and closing
|
||||
handshakes, independently of any data transfer. However we might be interested in
|
||||
identifying complete conversations with some data sent, and we are using the
|
||||
following bit values to build a filter value on the tcp.completeness field :
|
||||
|
||||
* 1 : SYN
|
||||
* 2 : SYN-ACK
|
||||
* 4 : ACK
|
||||
* 8 : DATA
|
||||
* 16 : FIN
|
||||
* 32 : RST
|
||||
|
||||
For example, a conversation containing only a three-way handshake will be found
|
||||
with the filter 'tcp.completeness==7' (1+2+4) while a complete conversation with
|
||||
data transfer will be found with a longer filter as closing a connection can be
|
||||
associated with FIN or RST packets, or even both :
|
||||
'tcp.completeness==31 or tcp.completeness==47 tcp.completeness==63'
|
||||
|
||||
[[ChAdvTimestamps]]
|
||||
|
||||
=== Time Stamps
|
||||
|
|
|
@ -140,6 +140,7 @@ static int hf_tcp_srcport = -1;
|
|||
static int hf_tcp_dstport = -1;
|
||||
static int hf_tcp_port = -1;
|
||||
static int hf_tcp_stream = -1;
|
||||
static int hf_tcp_completeness = -1;
|
||||
static int hf_tcp_seq = -1;
|
||||
static int hf_tcp_seq_abs = -1;
|
||||
static int hf_tcp_nxtseq = -1;
|
||||
|
@ -510,6 +511,16 @@ static gboolean tcp_display_process_info = FALSE;
|
|||
#define TCPOPT_MPTCP_MP_FAIL 0x6 /* Multipath TCP Fallback */
|
||||
#define TCPOPT_MPTCP_MP_FASTCLOSE 0x7 /* Multipath TCP Fast Close */
|
||||
|
||||
/*
|
||||
* Conversation Completeness values
|
||||
*/
|
||||
#define TCP_COMPLETENESS_SYNSENT 0x01 /* TCP SYN SENT */
|
||||
#define TCP_COMPLETENESS_SYNACK 0x02 /* TCP SYN ACK */
|
||||
#define TCP_COMPLETENESS_ACK 0x04 /* TCP ACK */
|
||||
#define TCP_COMPLETENESS_DATA 0x08 /* TCP data */
|
||||
#define TCP_COMPLETENESS_FIN 0x10 /* TCP FIN */
|
||||
#define TCP_COMPLETENESS_RST 0x20 /* TCP RST */
|
||||
|
||||
static const true_false_string tcp_option_user_to_granularity = {
|
||||
"Minutes", "Seconds"
|
||||
};
|
||||
|
@ -1334,6 +1345,71 @@ handle_export_pdu_conversation(packet_info *pinfo, tvbuff_t *tvb, int src_port,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* display the TCP Conversation Completeness
|
||||
* we of course pay much attention on complete conversations but also incomplete ones which
|
||||
* have a regular start, as in practice we are often looking for such thing
|
||||
*/
|
||||
void conversation_completeness_fill (gchar *buf, guint32 value)
|
||||
{
|
||||
switch(value) {
|
||||
case TCP_COMPLETENESS_SYNSENT:
|
||||
g_snprintf(buf, ITEM_LABEL_LENGTH, "Incomplete, SYN_SENT (%u)", value);
|
||||
break;
|
||||
case (TCP_COMPLETENESS_SYNSENT|
|
||||
TCP_COMPLETENESS_SYNACK):
|
||||
g_snprintf(buf, ITEM_LABEL_LENGTH, "Incomplete, CLIENT_ESTABLISHED (%u)", value);
|
||||
break;
|
||||
case (TCP_COMPLETENESS_SYNSENT|
|
||||
TCP_COMPLETENESS_SYNACK|
|
||||
TCP_COMPLETENESS_ACK):
|
||||
g_snprintf(buf, ITEM_LABEL_LENGTH, "Incomplete, ESTABLISHED (%u)", value);
|
||||
break;
|
||||
case (TCP_COMPLETENESS_SYNSENT|
|
||||
TCP_COMPLETENESS_SYNACK|
|
||||
TCP_COMPLETENESS_ACK|
|
||||
TCP_COMPLETENESS_DATA):
|
||||
g_snprintf(buf, ITEM_LABEL_LENGTH, "Incomplete, DATA (%u)", value);
|
||||
break;
|
||||
case (TCP_COMPLETENESS_SYNSENT|
|
||||
TCP_COMPLETENESS_SYNACK|
|
||||
TCP_COMPLETENESS_ACK|
|
||||
TCP_COMPLETENESS_DATA|
|
||||
TCP_COMPLETENESS_FIN):
|
||||
case (TCP_COMPLETENESS_SYNSENT|
|
||||
TCP_COMPLETENESS_SYNACK|
|
||||
TCP_COMPLETENESS_ACK|
|
||||
TCP_COMPLETENESS_DATA|
|
||||
TCP_COMPLETENESS_RST):
|
||||
case (TCP_COMPLETENESS_SYNSENT|
|
||||
TCP_COMPLETENESS_SYNACK|
|
||||
TCP_COMPLETENESS_ACK|
|
||||
TCP_COMPLETENESS_DATA|
|
||||
TCP_COMPLETENESS_FIN|
|
||||
TCP_COMPLETENESS_RST):
|
||||
g_snprintf(buf, ITEM_LABEL_LENGTH, "Complete, WITH_DATA (%u)", value);
|
||||
break;
|
||||
case (TCP_COMPLETENESS_SYNSENT|
|
||||
TCP_COMPLETENESS_SYNACK|
|
||||
TCP_COMPLETENESS_ACK|
|
||||
TCP_COMPLETENESS_FIN):
|
||||
case (TCP_COMPLETENESS_SYNSENT|
|
||||
TCP_COMPLETENESS_SYNACK|
|
||||
TCP_COMPLETENESS_ACK|
|
||||
TCP_COMPLETENESS_RST):
|
||||
case (TCP_COMPLETENESS_SYNSENT|
|
||||
TCP_COMPLETENESS_SYNACK|
|
||||
TCP_COMPLETENESS_ACK|
|
||||
TCP_COMPLETENESS_FIN|
|
||||
TCP_COMPLETENESS_RST):
|
||||
g_snprintf(buf, ITEM_LABEL_LENGTH, "Complete, NO_DATA (%u)", value);
|
||||
break;
|
||||
default:
|
||||
g_snprintf(buf, ITEM_LABEL_LENGTH, "Incomplete (%u)", value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* TCP structs and definitions */
|
||||
|
||||
/* **************************************************************************
|
||||
|
@ -6185,6 +6261,8 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
|||
proto_item *item;
|
||||
proto_tree *checksum_tree;
|
||||
gboolean icmp_ip = FALSE;
|
||||
guint8 conversation_completeness = 0;
|
||||
gboolean conversation_is_new = FALSE;
|
||||
|
||||
tcph = wmem_new0(wmem_packet_scope(), struct tcpheader);
|
||||
tcph->th_sport = tvb_get_ntohs(tvb, offset);
|
||||
|
@ -6271,6 +6349,8 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
|||
conv = conversation_new(pinfo->num, &pinfo->src,
|
||||
&pinfo->dst, ENDPOINT_TCP,
|
||||
pinfo->srcport, pinfo->destport, 0);
|
||||
/* we need to know when a conversation is new then we initialize the completeness correctly */
|
||||
conversation_is_new = TRUE;
|
||||
}
|
||||
tcpd=get_tcp_conversation_data(conv,pinfo);
|
||||
|
||||
|
@ -6292,6 +6372,9 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
|||
|
||||
conv=conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, ENDPOINT_TCP, pinfo->srcport, pinfo->destport, 0);
|
||||
tcpd=get_tcp_conversation_data(conv,pinfo);
|
||||
|
||||
/* As above, a new conversation starting with a SYN implies conversation completeness value 1 */
|
||||
tcpd->conversation_completeness = 1;
|
||||
}
|
||||
if(!tcpd->ta)
|
||||
tcp_analyze_get_acked_struct(pinfo->num, tcph->th_seq, tcph->th_ack, TRUE, tcpd);
|
||||
|
@ -6330,6 +6413,10 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
|||
item = proto_tree_add_uint(tcp_tree, hf_tcp_stream, tvb, offset, 0, tcpd->stream);
|
||||
proto_item_set_generated(item);
|
||||
|
||||
/* Display the completeness of this TCP conversation */
|
||||
item = proto_tree_add_uint(tcp_tree, hf_tcp_completeness, NULL, 0, 0, tcpd->conversation_completeness);
|
||||
proto_item_set_generated(item);
|
||||
|
||||
/* Copy the stream index into the header as well to make it available
|
||||
* to tap listeners.
|
||||
*/
|
||||
|
@ -6456,6 +6543,47 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
|||
return offset+12;
|
||||
}
|
||||
|
||||
/* initialize or move forward the conversation completeness */
|
||||
if(tcpd) {
|
||||
if(conversation_is_new) { /* pure SYN must be sought in new conversations only */
|
||||
if((tcph->th_flags&(TH_SYN|TH_ACK))==TH_SYN) {
|
||||
conversation_completeness |= TCP_COMPLETENESS_SYNSENT;
|
||||
if(tcph->th_seglen > 0) { /* TCP Fast Open */
|
||||
conversation_completeness |= TCP_COMPLETENESS_DATA;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
conversation_completeness = tcpd->conversation_completeness ;
|
||||
|
||||
/* SYN-ACK */
|
||||
if((tcph->th_flags&(TH_SYN|TH_ACK))==(TH_SYN|TH_ACK)) {
|
||||
conversation_completeness |= TCP_COMPLETENESS_SYNACK;
|
||||
}
|
||||
|
||||
/* ACKs */
|
||||
if((tcph->th_flags&(TH_SYN|TH_ACK))==(TH_ACK)) {
|
||||
if(tcph->th_seglen>0) { /* transporting some data */
|
||||
conversation_completeness |= TCP_COMPLETENESS_DATA;
|
||||
}
|
||||
else { /* pure ACK */
|
||||
conversation_completeness |= TCP_COMPLETENESS_ACK;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIN-ACK */
|
||||
if((tcph->th_flags&(TH_FIN|TH_ACK))==(TH_FIN|TH_ACK)) {
|
||||
conversation_completeness |= TCP_COMPLETENESS_FIN;
|
||||
}
|
||||
|
||||
/* RST */
|
||||
if(tcph->th_flags&(TH_RST)) {
|
||||
conversation_completeness |= TCP_COMPLETENESS_RST;
|
||||
}
|
||||
}
|
||||
}
|
||||
tcpd->conversation_completeness = conversation_completeness;
|
||||
|
||||
if (tcp_summary_in_tree) {
|
||||
if(tcph->th_flags&TH_ACK) {
|
||||
proto_item_append_text(ti, ", Ack: %u", tcph->th_ack);
|
||||
|
@ -7017,6 +7145,11 @@ proto_register_tcp(void)
|
|||
{ "Stream index", "tcp.stream", FT_UINT32, BASE_DEC, NULL, 0x0,
|
||||
NULL, HFILL }},
|
||||
|
||||
{ &hf_tcp_completeness,
|
||||
{ "Conversation completeness", "tcp.completeness", FT_UINT8,
|
||||
BASE_CUSTOM, CF_FUNC(conversation_completeness_fill), 0x0,
|
||||
"The completeness of the conversation capture", HFILL }},
|
||||
|
||||
{ &hf_tcp_seq,
|
||||
{ "Sequence Number", "tcp.seq", FT_UINT32, BASE_DEC, NULL, 0x0,
|
||||
NULL, HFILL }},
|
||||
|
|
|
@ -456,6 +456,13 @@ struct tcp_analysis {
|
|||
* can exist without any meta
|
||||
*/
|
||||
struct mptcp_analysis* mptcp_analysis;
|
||||
|
||||
/* Track the TCP conversation completeness, as the capture might
|
||||
* contain all parts of a TCP flow (establishment, data, clearing) or
|
||||
* just some parts if we jumped on the bandwagon of an already established
|
||||
* connection or left before it was terminated explicitly
|
||||
*/
|
||||
guint8 conversation_completeness;
|
||||
};
|
||||
|
||||
/* Structure that keeps per packet data. First used to be able
|
||||
|
|
Loading…
Reference in New Issue