2013-08-27 18:13:20 +00:00
|
|
|
/* tap-tcp-stream.c
|
|
|
|
* TCP stream statistics
|
|
|
|
* Originally from tcp_graph.c by Pavel Mores <pvl@uh.cz>
|
|
|
|
* Win32 port: rwh@unifiedtech.com
|
|
|
|
*
|
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
2018-04-30 09:47:58 +02:00
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
2013-08-27 18:13:20 +00:00
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
2013-11-10 15:59:37 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2013-08-27 18:13:20 +00:00
|
|
|
#include <file.h>
|
|
|
|
|
|
|
|
#include <epan/epan_dissect.h>
|
|
|
|
#include <epan/packet.h>
|
|
|
|
#include <epan/tap.h>
|
|
|
|
|
|
|
|
#include <epan/dissectors/packet-tcp.h>
|
|
|
|
|
|
|
|
#include "ui/simple_dialog.h"
|
|
|
|
|
|
|
|
#include "tap-tcp-stream.h"
|
|
|
|
|
Qt: Make TCPStreamDialog event-driven, prevent crash on closing
Make the TCP Stream Dialog react to the CaptureEvents when retapping
is done. This has the advantage that the signal isn't received when
the TCPStreamDialog has been destroyed, instead of always manipulating
the UI elements after the potentially very long retap is finished.
This uses the CaptureFile QT object instead of the capture_file pointer
directly.
The TCP Stream Dialog taps and then disconnects, instead of staying
connected as a tap. Continue with that behavior, but allow the existing
graph to still be changed after the file is closed (aside from the
stream number, which requires a re-tap.)
Disable the stream number spinbox during tapping with setReadOnly, which
achieves the goal of disabling it but not affecting focus more simply.
Completely disable it when the file is closed, because it won't be
enabled again.
Remove the tap listener when destroying the dialog if we're still tapping.
(depends on c79d79f2e16c9e6bd9a3d9a9837cfbff13300c4f) This will produce
a console warning when tapping finishes (no listener found with that tap
data) if the dialog has already been closed, but is better than crashing.
We could remove the tap listener upon the captureEvent in the Qt dialog
to avoid the console warning instead of in graph_segment_list_get,
changing its behavior.
Free the graph segments as the tap reset callback, which is a little
cleaner.
Fix #20426
2025-03-06 21:29:07 -05:00
|
|
|
static void
|
|
|
|
tapall_tcpip_reset(void *tapdata)
|
|
|
|
{
|
|
|
|
struct tcp_graph *tg = (struct tcp_graph *)tapdata;
|
|
|
|
graph_segment_list_free(tg);
|
|
|
|
}
|
|
|
|
|
2018-12-31 19:36:12 -08:00
|
|
|
static tap_packet_status
|
2022-06-09 17:47:35 +02:00
|
|
|
tapall_tcpip_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip, tap_flags_t flags _U_)
|
2013-08-27 18:13:20 +00:00
|
|
|
{
|
2025-03-07 07:23:39 -05:00
|
|
|
struct tcp_graph *tg = (struct tcp_graph *)pct;
|
2013-08-27 18:13:20 +00:00
|
|
|
const struct tcpheader *tcphdr = (const struct tcpheader *)vip;
|
|
|
|
|
2013-09-12 21:37:47 +00:00
|
|
|
if (tg->stream == tcphdr->th_stream
|
|
|
|
&& (tg->src_address.type == AT_NONE || tg->dst_address.type == AT_NONE)) {
|
|
|
|
/*
|
|
|
|
* We only know the stream number. Fill in our connection data.
|
|
|
|
* We assume that the server response is more interesting.
|
|
|
|
*/
|
2024-05-05 11:41:15 -04:00
|
|
|
bool server_is_src;
|
|
|
|
if (tcphdr->th_flags & TH_SYN) {
|
|
|
|
if (tcphdr->th_flags & TH_ACK) {
|
|
|
|
/* SYN-ACK packet, so the server is the source. */
|
|
|
|
server_is_src = true;
|
|
|
|
} else {
|
|
|
|
/* SYN packet, so the server is the destination. */
|
|
|
|
server_is_src = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Fallback to assuming the lower numbered port is the server. */
|
|
|
|
server_is_src = tcphdr->th_sport < tcphdr->th_dport;
|
|
|
|
}
|
|
|
|
if (server_is_src) {
|
|
|
|
copy_address(&tg->src_address, &tcphdr->ip_src);
|
|
|
|
tg->src_port = tcphdr->th_sport;
|
|
|
|
copy_address(&tg->dst_address, &tcphdr->ip_dst);
|
|
|
|
tg->dst_port = tcphdr->th_dport;
|
|
|
|
} else {
|
|
|
|
copy_address(&tg->src_address, &tcphdr->ip_dst);
|
|
|
|
tg->src_port = tcphdr->th_dport;
|
|
|
|
copy_address(&tg->dst_address, &tcphdr->ip_src);
|
|
|
|
tg->dst_port = tcphdr->th_sport;
|
|
|
|
}
|
2013-09-12 21:37:47 +00:00
|
|
|
}
|
|
|
|
|
2013-08-27 18:13:20 +00:00
|
|
|
if (compare_headers(&tg->src_address, &tg->dst_address,
|
|
|
|
tg->src_port, tg->dst_port,
|
|
|
|
&tcphdr->ip_src, &tcphdr->ip_dst,
|
|
|
|
tcphdr->th_sport, tcphdr->th_dport,
|
2025-03-07 07:23:39 -05:00
|
|
|
COMPARE_ANY_DIR)
|
2013-09-09 01:40:06 +00:00
|
|
|
&& tg->stream == tcphdr->th_stream)
|
2013-08-27 18:13:20 +00:00
|
|
|
{
|
2018-03-17 19:33:11 +01:00
|
|
|
struct segment *segment = g_new(struct segment, 1);
|
2013-08-27 18:13:20 +00:00
|
|
|
segment->next = NULL;
|
2016-01-23 19:40:51 -08:00
|
|
|
segment->num = pinfo->num;
|
2024-03-29 18:08:09 -07:00
|
|
|
segment->rel_secs = (uint32_t)pinfo->rel_ts.secs;
|
2013-08-27 18:13:20 +00:00
|
|
|
segment->rel_usecs = pinfo->rel_ts.nsecs/1000;
|
2013-09-09 01:40:06 +00:00
|
|
|
/* Currently unused
|
2021-04-28 13:16:29 -07:00
|
|
|
segment->abs_secs = pinfo->abs_ts.secs;
|
2016-01-22 19:57:32 -08:00
|
|
|
segment->abs_usecs = pinfo->abs_ts.nsecs/1000;
|
2013-09-09 01:40:06 +00:00
|
|
|
*/
|
2024-05-06 10:43:38 -04:00
|
|
|
/* tcphdr->th_rawseq is always the absolute sequence number.
|
|
|
|
* tcphdr->th_seq is either the relative or absolute sequence number
|
|
|
|
* depending on the TCP dissector preferences.
|
2024-05-20 10:13:10 -04:00
|
|
|
* The sack entries are also either the relative or absolute sequence
|
|
|
|
* number depending on the TCP dissector preferences.
|
2024-05-06 10:43:38 -04:00
|
|
|
* The TCP stream graphs have their own action / button press to
|
2024-05-20 10:13:10 -04:00
|
|
|
* switch between relative and absolute sequence numbers on the fly;
|
|
|
|
* if the TCP dissector hasn't calculated the relative sequence numbers,
|
|
|
|
* the tap will do so. (XXX - The calculation is cheap enough that we
|
|
|
|
* could do it here and store the offsets at the graph level to save
|
|
|
|
* memory. The TCP dissector could include its calculated base seq in
|
|
|
|
* the tap information to ensure consistency.)
|
2024-05-06 10:43:38 -04:00
|
|
|
*/
|
2024-05-20 10:13:10 -04:00
|
|
|
segment->th_seq = tcphdr->th_seq;
|
|
|
|
segment->th_ack = tcphdr->th_ack;
|
|
|
|
segment->th_rawseq = tcphdr->th_rawseq;
|
|
|
|
segment->th_rawack = tcphdr->th_rawack;
|
2013-08-27 18:13:20 +00:00
|
|
|
segment->th_win = tcphdr->th_win;
|
|
|
|
segment->th_flags = tcphdr->th_flags;
|
|
|
|
segment->th_sport = tcphdr->th_sport;
|
|
|
|
segment->th_dport = tcphdr->th_dport;
|
|
|
|
segment->th_seglen = tcphdr->th_seglen;
|
2015-10-21 11:46:49 -07:00
|
|
|
copy_address(&segment->ip_src, &tcphdr->ip_src);
|
|
|
|
copy_address(&segment->ip_dst, &tcphdr->ip_dst);
|
2013-08-27 18:13:20 +00:00
|
|
|
|
2025-01-07 06:37:50 +00:00
|
|
|
segment->ack_karn=tcphdr->flagkarn;
|
|
|
|
|
2013-08-27 18:13:20 +00:00
|
|
|
segment->num_sack_ranges = MIN(MAX_TCP_SACK_RANGES, tcphdr->num_sack_ranges);
|
|
|
|
if (segment->num_sack_ranges > 0) {
|
|
|
|
/* Copy entries in the order they happen */
|
|
|
|
memcpy(&segment->sack_left_edge, &tcphdr->sack_left_edge, sizeof(segment->sack_left_edge));
|
|
|
|
memcpy(&segment->sack_right_edge, &tcphdr->sack_right_edge, sizeof(segment->sack_right_edge));
|
|
|
|
}
|
|
|
|
|
2025-03-07 07:23:39 -05:00
|
|
|
if (tg->segments) {
|
|
|
|
tg->last->next = segment;
|
2013-08-27 18:13:20 +00:00
|
|
|
} else {
|
2025-03-07 07:23:39 -05:00
|
|
|
tg->segments = segment;
|
2013-08-27 18:13:20 +00:00
|
|
|
}
|
2025-03-07 07:23:39 -05:00
|
|
|
tg->last = segment;
|
2013-08-27 18:13:20 +00:00
|
|
|
}
|
|
|
|
|
2018-12-31 19:36:12 -08:00
|
|
|
return TAP_PACKET_DONT_REDRAW;
|
2013-08-27 18:13:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* here we collect all the external data we will ever need */
|
|
|
|
void
|
2020-04-13 23:00:48 +02:00
|
|
|
graph_segment_list_get(capture_file *cf, struct tcp_graph *tg)
|
2013-08-27 18:13:20 +00:00
|
|
|
{
|
2016-06-19 11:01:56 +02:00
|
|
|
GString *error_string;
|
2013-08-27 18:13:20 +00:00
|
|
|
|
2018-03-17 19:36:32 +01:00
|
|
|
if (!cf || !tg) {
|
|
|
|
return;
|
|
|
|
}
|
2013-08-27 18:13:20 +00:00
|
|
|
|
|
|
|
/* rescan all the packets and pick up all interesting tcp headers.
|
|
|
|
* we only filter for TCP here for speed and do the actual compare
|
|
|
|
* in the tap listener
|
|
|
|
*/
|
Qt: Make TCPStreamDialog event-driven, prevent crash on closing
Make the TCP Stream Dialog react to the CaptureEvents when retapping
is done. This has the advantage that the signal isn't received when
the TCPStreamDialog has been destroyed, instead of always manipulating
the UI elements after the potentially very long retap is finished.
This uses the CaptureFile QT object instead of the capture_file pointer
directly.
The TCP Stream Dialog taps and then disconnects, instead of staying
connected as a tap. Continue with that behavior, but allow the existing
graph to still be changed after the file is closed (aside from the
stream number, which requires a re-tap.)
Disable the stream number spinbox during tapping with setReadOnly, which
achieves the goal of disabling it but not affecting focus more simply.
Completely disable it when the file is closed, because it won't be
enabled again.
Remove the tap listener when destroying the dialog if we're still tapping.
(depends on c79d79f2e16c9e6bd9a3d9a9837cfbff13300c4f) This will produce
a console warning when tapping finishes (no listener found with that tap
data) if the dialog has already been closed, but is better than crashing.
We could remove the tap listener upon the captureEvent in the Qt dialog
to avoid the console warning instead of in graph_segment_list_get,
changing its behavior.
Free the graph segments as the tap reset callback, which is a little
cleaner.
Fix #20426
2025-03-06 21:29:07 -05:00
|
|
|
error_string = register_tap_listener("tcp", tg, "tcp", 0, tapall_tcpip_reset, tapall_tcpip_packet, NULL, NULL);
|
2013-08-27 18:13:20 +00:00
|
|
|
if (error_string) {
|
|
|
|
fprintf(stderr, "wireshark: Couldn't register tcp_graph tap: %s\n",
|
2016-06-19 11:01:56 +02:00
|
|
|
error_string->str);
|
2024-07-05 08:04:12 +02:00
|
|
|
g_string_free(error_string, TRUE);
|
2013-08-27 18:13:20 +00:00
|
|
|
exit(1); /* XXX: fix this */
|
|
|
|
}
|
|
|
|
cf_retap_packets(cf);
|
2025-03-07 07:23:39 -05:00
|
|
|
remove_tap_listener(tg);
|
2013-08-27 18:13:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
graph_segment_list_free(struct tcp_graph *tg)
|
|
|
|
{
|
|
|
|
struct segment *segment;
|
|
|
|
|
2020-04-13 23:00:48 +02:00
|
|
|
free_address(&tg->src_address);
|
|
|
|
free_address(&tg->dst_address);
|
|
|
|
|
2013-08-27 18:13:20 +00:00
|
|
|
while (tg->segments) {
|
|
|
|
segment = tg->segments->next;
|
2020-04-13 23:00:48 +02:00
|
|
|
free_address(&tg->segments->ip_src);
|
|
|
|
free_address(&tg->segments->ip_dst);
|
2013-08-27 18:13:20 +00:00
|
|
|
g_free(tg->segments);
|
|
|
|
tg->segments = segment;
|
|
|
|
}
|
2025-03-07 07:23:39 -05:00
|
|
|
tg->last = NULL;
|
2013-08-27 18:13:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2024-03-29 18:08:09 -07:00
|
|
|
compare_headers(address *saddr1, address *daddr1, uint16_t sport1, uint16_t dport1, const address *saddr2, const address *daddr2, uint16_t sport2, uint16_t dport2, int dir)
|
2013-08-27 18:13:20 +00:00
|
|
|
{
|
|
|
|
int dir1, dir2;
|
|
|
|
|
2015-10-21 11:46:49 -07:00
|
|
|
dir1 = ((!(cmp_address(saddr1, saddr2))) &&
|
|
|
|
(!(cmp_address(daddr1, daddr2))) &&
|
2013-08-27 18:13:20 +00:00
|
|
|
(sport1==sport2) &&
|
|
|
|
(dport1==dport2));
|
|
|
|
|
|
|
|
if (dir == COMPARE_CURR_DIR) {
|
|
|
|
return dir1;
|
|
|
|
} else {
|
2015-10-21 11:46:49 -07:00
|
|
|
dir2 = ((!(cmp_address(saddr1, daddr2))) &&
|
|
|
|
(!(cmp_address(daddr1, saddr2))) &&
|
2013-08-27 18:13:20 +00:00
|
|
|
(sport1 == dport2) &&
|
|
|
|
(dport1 == sport2));
|
|
|
|
return dir1 || dir2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-04 23:15:59 +00:00
|
|
|
int
|
|
|
|
get_num_dsegs(struct tcp_graph *tg)
|
|
|
|
{
|
|
|
|
int count;
|
|
|
|
struct segment *tmp;
|
|
|
|
|
|
|
|
for (tmp=tg->segments, count=0; tmp; tmp=tmp->next) {
|
|
|
|
if (compare_headers(&tg->src_address, &tg->dst_address,
|
|
|
|
tg->src_port, tg->dst_port,
|
|
|
|
&tmp->ip_src, &tmp->ip_dst,
|
|
|
|
tmp->th_sport, tmp->th_dport,
|
|
|
|
COMPARE_CURR_DIR)) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
get_num_acks(struct tcp_graph *tg, int *num_sack_ranges)
|
|
|
|
{
|
|
|
|
int count;
|
|
|
|
struct segment *tmp;
|
|
|
|
|
|
|
|
for (tmp = tg->segments, count=0; tmp; tmp = tmp->next) {
|
|
|
|
if (!compare_headers(&tg->src_address, &tg->dst_address,
|
|
|
|
tg->src_port, tg->dst_port,
|
|
|
|
&tmp->ip_src, &tmp->ip_dst,
|
|
|
|
tmp->th_sport, tmp->th_dport,
|
|
|
|
COMPARE_CURR_DIR)) {
|
|
|
|
count++;
|
|
|
|
*num_sack_ranges += tmp->num_sack_ranges;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2013-08-27 18:13:20 +00:00
|
|
|
typedef struct _th_t {
|
|
|
|
int num_hdrs;
|
|
|
|
#define MAX_SUPPORTED_TCP_HEADERS 8
|
|
|
|
struct tcpheader *tcphdrs[MAX_SUPPORTED_TCP_HEADERS];
|
|
|
|
} th_t;
|
|
|
|
|
2018-12-31 19:36:12 -08:00
|
|
|
static tap_packet_status
|
2022-06-09 17:47:35 +02:00
|
|
|
tap_tcpip_packet(void *pct, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *vip, tap_flags_t flags _U_)
|
2013-08-27 18:13:20 +00:00
|
|
|
{
|
|
|
|
int n;
|
2024-03-29 18:08:09 -07:00
|
|
|
bool is_unique = true;
|
2013-08-27 18:13:20 +00:00
|
|
|
th_t *th = (th_t *)pct;
|
|
|
|
const struct tcpheader *header = (const struct tcpheader *)vip;
|
|
|
|
|
|
|
|
/* Check new header details against any/all stored ones */
|
|
|
|
for (n=0; n < th->num_hdrs; n++) {
|
|
|
|
struct tcpheader *stored = th->tcphdrs[n];
|
|
|
|
|
|
|
|
if (compare_headers(&stored->ip_src, &stored->ip_dst,
|
|
|
|
stored->th_sport, stored->th_dport,
|
|
|
|
&header->ip_src, &header->ip_dst,
|
|
|
|
header->th_sport, stored->th_dport,
|
2018-03-17 19:36:32 +01:00
|
|
|
COMPARE_CURR_DIR)) {
|
2024-03-29 18:08:09 -07:00
|
|
|
is_unique = false;
|
2013-08-27 18:13:20 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add address if unique and have space for it */
|
|
|
|
if (is_unique && (th->num_hdrs < MAX_SUPPORTED_TCP_HEADERS)) {
|
|
|
|
/* Need to take a deep copy of the tap struct, it may not be valid
|
|
|
|
to read after this function returns? */
|
2018-03-17 19:33:11 +01:00
|
|
|
th->tcphdrs[th->num_hdrs] = g_new(struct tcpheader, 1);
|
2013-08-27 18:13:20 +00:00
|
|
|
*(th->tcphdrs[th->num_hdrs]) = *header;
|
2015-10-21 11:46:49 -07:00
|
|
|
copy_address(&th->tcphdrs[th->num_hdrs]->ip_src, &header->ip_src);
|
|
|
|
copy_address(&th->tcphdrs[th->num_hdrs]->ip_dst, &header->ip_dst);
|
2013-08-27 18:13:20 +00:00
|
|
|
|
|
|
|
th->num_hdrs++;
|
|
|
|
}
|
|
|
|
|
2018-12-31 19:36:12 -08:00
|
|
|
return TAP_PACKET_DONT_REDRAW;
|
2013-08-27 18:13:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX should be enhanced so that if we have multiple TCP layers in the trace
|
|
|
|
* then present the user with a dialog where the user can select WHICH tcp
|
|
|
|
* session to graph.
|
|
|
|
*/
|
2024-03-29 18:08:09 -07:00
|
|
|
uint32_t
|
2020-04-13 23:00:48 +02:00
|
|
|
select_tcpip_session(capture_file *cf)
|
2013-08-27 18:13:20 +00:00
|
|
|
{
|
|
|
|
frame_data *fdata;
|
|
|
|
epan_dissect_t edt;
|
|
|
|
dfilter_t *sfcode;
|
2024-03-29 18:08:09 -07:00
|
|
|
uint32_t th_stream;
|
2022-11-19 19:21:19 +00:00
|
|
|
df_error_t *df_err;
|
2016-06-19 11:01:56 +02:00
|
|
|
GString *error_string;
|
2013-08-27 18:13:20 +00:00
|
|
|
th_t th = {0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}};
|
|
|
|
|
2020-04-13 23:00:48 +02:00
|
|
|
if (!cf) {
|
2024-03-29 18:08:09 -07:00
|
|
|
return UINT32_MAX;
|
2018-03-17 19:36:32 +01:00
|
|
|
}
|
2014-02-25 15:42:35 -05:00
|
|
|
|
2013-08-27 18:13:20 +00:00
|
|
|
/* no real filter yet */
|
2022-11-19 19:21:19 +00:00
|
|
|
if (!dfilter_compile("tcp", &sfcode, &df_err)) {
|
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", df_err->msg);
|
2023-04-15 00:18:53 +01:00
|
|
|
df_error_free(&df_err);
|
2024-03-29 18:08:09 -07:00
|
|
|
return UINT32_MAX;
|
2013-08-27 18:13:20 +00:00
|
|
|
}
|
|
|
|
|
2014-05-24 11:28:30 -07:00
|
|
|
/* dissect the current record */
|
2019-04-14 22:14:15 -07:00
|
|
|
if (!cf_read_current_record(cf)) {
|
2024-03-29 18:08:09 -07:00
|
|
|
return UINT32_MAX; /* error reading the record */
|
2018-03-17 19:36:32 +01:00
|
|
|
}
|
2013-08-27 18:13:20 +00:00
|
|
|
|
2019-04-14 22:14:15 -07:00
|
|
|
fdata = cf->current_frame;
|
2013-08-27 18:13:20 +00:00
|
|
|
|
2018-07-20 17:07:19 -07:00
|
|
|
error_string = register_tap_listener("tcp", &th, NULL, 0, NULL, tap_tcpip_packet, NULL, NULL);
|
2013-08-27 18:13:20 +00:00
|
|
|
if (error_string) {
|
|
|
|
fprintf(stderr, "wireshark: Couldn't register tcp_graph tap: %s\n",
|
2016-06-19 11:01:56 +02:00
|
|
|
error_string->str);
|
2024-07-05 08:04:12 +02:00
|
|
|
g_string_free(error_string, TRUE);
|
2025-04-17 18:26:13 -04:00
|
|
|
return UINT32_MAX;
|
2013-08-27 18:13:20 +00:00
|
|
|
}
|
|
|
|
|
2024-03-29 18:08:09 -07:00
|
|
|
epan_dissect_init(&edt, cf->epan, true, false);
|
2017-04-11 21:56:14 -07:00
|
|
|
epan_dissect_prime_with_dfilter(&edt, sfcode);
|
2024-12-29 14:04:53 -08:00
|
|
|
epan_dissect_run_with_taps(&edt, cf->cd_t, &cf->rec, fdata, NULL);
|
2013-08-27 18:13:20 +00:00
|
|
|
epan_dissect_cleanup(&edt);
|
|
|
|
remove_tap_listener(&th);
|
2020-04-13 23:00:48 +02:00
|
|
|
dfilter_free(sfcode);
|
2013-08-27 18:13:20 +00:00
|
|
|
|
|
|
|
if (th.num_hdrs == 0) {
|
|
|
|
/* This "shouldn't happen", as our menu items shouldn't
|
|
|
|
* even be enabled if the selected packet isn't a TCP
|
|
|
|
* segment, as tcp_graph_selected_packet_enabled() is used
|
|
|
|
* to determine whether to enable any of our menu items. */
|
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
2016-01-20 15:15:23 +01:00
|
|
|
"Selected packet isn't a TCP segment or is truncated");
|
2024-03-29 18:08:09 -07:00
|
|
|
return UINT32_MAX;
|
2013-08-27 18:13:20 +00:00
|
|
|
}
|
|
|
|
/* XXX fix this later, we should show a dialog allowing the user
|
|
|
|
to select which session he wants here
|
|
|
|
*/
|
|
|
|
if (th.num_hdrs > 1) {
|
|
|
|
/* can only handle a single tcp layer yet */
|
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
|
|
|
"The selected packet has more than one TCP unique conversation "
|
|
|
|
"in it.");
|
2024-03-29 18:08:09 -07:00
|
|
|
return UINT32_MAX;
|
2013-08-27 18:13:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* For now, still always choose the first/only one */
|
2020-04-13 23:00:48 +02:00
|
|
|
th_stream = th.tcphdrs[0]->th_stream;
|
|
|
|
|
|
|
|
for (int n = 0; n < th.num_hdrs; n++) {
|
|
|
|
free_address(&th.tcphdrs[n]->ip_src);
|
|
|
|
free_address(&th.tcphdrs[n]->ip_dst);
|
|
|
|
g_free(th.tcphdrs[n]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return th_stream;
|
2013-08-27 18:13:20 +00:00
|
|
|
}
|
|
|
|
|
2025-01-07 06:37:50 +00:00
|
|
|
bool rtt_is_retrans(struct rtt_unack *list, unsigned int seqno)
|
2013-09-08 01:25:27 +00:00
|
|
|
{
|
2017-01-17 20:30:26 -08:00
|
|
|
struct rtt_unack *u;
|
2013-09-08 01:25:27 +00:00
|
|
|
|
|
|
|
for (u=list; u; u=u->next) {
|
2017-01-17 20:30:26 -08:00
|
|
|
if (tcp_seq_eq_or_after(seqno, u->seqno) &&
|
2018-03-17 19:36:32 +01:00
|
|
|
tcp_seq_before(seqno, u->end_seqno)) {
|
2024-03-29 18:08:09 -07:00
|
|
|
return true;
|
2018-03-17 19:36:32 +01:00
|
|
|
}
|
2013-09-08 01:25:27 +00:00
|
|
|
}
|
2024-03-29 18:08:09 -07:00
|
|
|
return false;
|
2013-09-08 01:25:27 +00:00
|
|
|
}
|
|
|
|
|
2017-01-17 20:30:26 -08:00
|
|
|
struct rtt_unack *
|
|
|
|
rtt_get_new_unack(double time_val, unsigned int seqno, unsigned int seglen)
|
2013-09-08 01:25:27 +00:00
|
|
|
{
|
2017-01-17 20:30:26 -08:00
|
|
|
struct rtt_unack *u;
|
2013-09-08 01:25:27 +00:00
|
|
|
|
2018-03-17 19:33:11 +01:00
|
|
|
u = g_new(struct rtt_unack, 1);
|
2013-09-08 01:25:27 +00:00
|
|
|
u->next = NULL;
|
|
|
|
u->time = time_val;
|
|
|
|
u->seqno = seqno;
|
2017-01-17 20:30:26 -08:00
|
|
|
u->end_seqno = seqno + seglen;
|
2013-09-08 01:25:27 +00:00
|
|
|
return u;
|
|
|
|
}
|
|
|
|
|
2017-01-17 20:30:26 -08:00
|
|
|
void rtt_put_unack_on_list(struct rtt_unack **l, struct rtt_unack *new_unack)
|
2013-09-08 01:25:27 +00:00
|
|
|
{
|
2017-01-17 20:30:26 -08:00
|
|
|
struct rtt_unack *u, *list = *l;
|
2013-09-08 01:25:27 +00:00
|
|
|
|
|
|
|
for (u=list; u; u=u->next) {
|
2018-03-17 19:36:32 +01:00
|
|
|
if (!u->next) {
|
2013-09-08 01:25:27 +00:00
|
|
|
break;
|
2018-03-17 19:36:32 +01:00
|
|
|
}
|
2013-09-08 01:25:27 +00:00
|
|
|
}
|
2018-03-17 19:36:32 +01:00
|
|
|
if (u) {
|
2013-09-08 01:25:27 +00:00
|
|
|
u->next = new_unack;
|
2018-03-17 19:36:32 +01:00
|
|
|
} else {
|
2013-09-08 01:25:27 +00:00
|
|
|
*l = new_unack;
|
2018-03-17 19:36:32 +01:00
|
|
|
}
|
2013-09-08 01:25:27 +00:00
|
|
|
}
|
|
|
|
|
2017-01-17 20:30:26 -08:00
|
|
|
void rtt_delete_unack_from_list(struct rtt_unack **l, struct rtt_unack *dead)
|
2013-09-08 01:25:27 +00:00
|
|
|
{
|
2017-01-17 20:30:26 -08:00
|
|
|
struct rtt_unack *u, *list = *l;
|
2013-09-08 01:25:27 +00:00
|
|
|
|
2018-03-17 19:36:32 +01:00
|
|
|
if (!dead || !list) {
|
2013-09-08 01:25:27 +00:00
|
|
|
return;
|
2018-03-17 19:36:32 +01:00
|
|
|
}
|
2013-09-08 01:25:27 +00:00
|
|
|
|
|
|
|
if (dead == list) {
|
|
|
|
*l = list->next;
|
|
|
|
g_free(list);
|
|
|
|
} else {
|
|
|
|
for (u=list; u; u=u->next) {
|
|
|
|
if (u->next == dead) {
|
|
|
|
u->next = u->next->next;
|
|
|
|
g_free(dead);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-17 20:30:26 -08:00
|
|
|
void rtt_destroy_unack_list(struct rtt_unack **l ) {
|
|
|
|
while (*l) {
|
|
|
|
struct rtt_unack *head = *l;
|
|
|
|
*l = head->next;
|
|
|
|
g_free(head);
|
|
|
|
}
|
|
|
|
}
|