776 lines
28 KiB
C
776 lines
28 KiB
C
/* packet-tcpclv3.c
|
|
* References:
|
|
* RFC 7242: https://tools.ietf.org/html/rfc7242
|
|
*
|
|
* Copyright 2006-2007 The MITRE Corporation.
|
|
* All Rights Reserved.
|
|
* Approved for Public Release; Distribution Unlimited.
|
|
* Tracking Number 07-0090.
|
|
*
|
|
* The US Government will not be charged any license fee and/or royalties
|
|
* related to this software. Neither name of The MITRE Corporation; nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*
|
|
* Specification reference:
|
|
* RFC 5050
|
|
* https://tools.ietf.org/html/rfc5050
|
|
*/
|
|
|
|
/*
|
|
* Modifications were made to this file under designation MFS-33289-1 and
|
|
* are Copyright 2015 United States Government as represented by NASA
|
|
* Marshall Space Flight Center. All Rights Reserved.
|
|
*
|
|
* Released under the GNU GPL with NASA legal approval granted 2016-06-10.
|
|
*
|
|
* The subject software is provided "AS IS" WITHOUT ANY WARRANTY of any kind,
|
|
* either expressed, implied or statutory and this agreement does not,
|
|
* in any manner, constitute an endorsement by government agency of any
|
|
* results, designs or products resulting from use of the subject software.
|
|
* See the Agreement for the specific language governing permissions and
|
|
* limitations.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <epan/packet.h>
|
|
#include <epan/reassemble.h>
|
|
#include <epan/expert.h>
|
|
#include "packet-tcpclv3.h"
|
|
#include "packet-bpv6.h"
|
|
#include "packet-tcp.h"
|
|
|
|
/* For Reassembling TCP Convergence Layer segments */
|
|
static reassembly_table msg_reassembly_table;
|
|
|
|
static const char magic[] = {'d', 't', 'n', '!'};
|
|
|
|
static int proto_tcp_conv = -1;
|
|
|
|
/* TCP Convergence Header Variables */
|
|
static int hf_tcp_convergence_pkt_type = -1;
|
|
|
|
/* Refuse-Bundle reason code */
|
|
static int hf_dtn_refuse_bundle_reason_code = -1;
|
|
|
|
static int hf_contact_hdr_version = -1;
|
|
static int hf_contact_hdr_flags = -1;
|
|
static int hf_contact_hdr_keep_alive = -1;
|
|
static int hf_contact_hdr_flags_ack_req = -1;
|
|
static int hf_contact_hdr_flags_frag_enable = -1;
|
|
static int hf_contact_hdr_flags_nak = -1;
|
|
static int hf_contact_hdr_magic = -1;
|
|
static int hf_contact_hdr_local_eid_length = -1;
|
|
static int hf_contact_hdr_local_eid = -1;
|
|
|
|
/* TCP Convergence Data Header Variables */
|
|
static int hf_tcp_convergence_data_procflags = -1;
|
|
static int hf_tcp_convergence_data_procflags_start = -1;
|
|
static int hf_tcp_convergence_data_procflags_end = -1;
|
|
static int hf_tcp_convergence_data_segment_length = -1;
|
|
|
|
/* TCP Convergence Ack Variables */
|
|
static int hf_tcp_convergence_ack_length = -1;
|
|
|
|
/* TCP Convergence Shutdown Header Variables */
|
|
static int hf_tcp_convergence_shutdown_flags = -1;
|
|
static int hf_tcp_convergence_shutdown_flags_reason = -1;
|
|
static int hf_tcp_convergence_shutdown_flags_delay = -1;
|
|
static int hf_tcp_convergence_shutdown_reason = -1;
|
|
static int hf_tcp_convergence_shutdown_delay = -1;
|
|
|
|
/*TCP Convergence Layer Reassembly boilerplate*/
|
|
static int hf_msg_fragments = -1;
|
|
static int hf_msg_fragment = -1;
|
|
static int hf_msg_fragment_overlap = -1;
|
|
static int hf_msg_fragment_overlap_conflicts = -1;
|
|
static int hf_msg_fragment_multiple_tails = -1;
|
|
static int hf_msg_fragment_too_long_fragment = -1;
|
|
static int hf_msg_fragment_error = -1;
|
|
static int hf_msg_fragment_count = -1;
|
|
static int hf_msg_reassembled_in = -1;
|
|
static int hf_msg_reassembled_length = -1;
|
|
|
|
/* Tree Node Variables */
|
|
static gint ett_conv_flags = -1;
|
|
static gint ett_shutdown_flags = -1;
|
|
static gint ett_contact_hdr_flags = -1;
|
|
static gint ett_tcp_conv = -1;
|
|
static gint ett_tcp_conv_hdr = -1;
|
|
static gint ett_msg_fragment = -1;
|
|
static gint ett_msg_fragments = -1;
|
|
|
|
static expert_field ei_tcp_convergence_data_flags = EI_INIT;
|
|
static expert_field ei_tcp_convergence_segment_length = EI_INIT;
|
|
static expert_field ei_tcp_convergence_ack_length = EI_INIT;
|
|
|
|
|
|
static dissector_handle_t bundle_handle;
|
|
|
|
typedef struct dictionary_data {
|
|
int bundle_header_dict_length;
|
|
|
|
int dest_scheme_offset;
|
|
int dst_scheme_pos;
|
|
int dst_scheme_len;
|
|
int source_scheme_offset;
|
|
int src_scheme_pos;
|
|
int src_scheme_len;
|
|
int report_scheme_offset;
|
|
int rpt_scheme_pos;
|
|
int rpt_scheme_len;
|
|
int cust_scheme_offset;
|
|
int cust_scheme_pos;
|
|
int cust_scheme_len;
|
|
int dest_ssp_offset;
|
|
int dst_ssp_len;
|
|
int source_ssp_offset;
|
|
int src_ssp_len;
|
|
int report_ssp_offset;
|
|
int rpt_ssp_len;
|
|
int cust_ssp_offset;
|
|
int cust_ssp_len;
|
|
|
|
} dictionary_data_t;
|
|
|
|
|
|
static const value_string packet_type_vals[] = {
|
|
{((TCP_CONVERGENCE_DATA_SEGMENT>>4) & 0x0F), "Data"},
|
|
{((TCP_CONVERGENCE_ACK_SEGMENT>>4) & 0x0F), "Ack"},
|
|
{((TCP_CONVERGENCE_REFUSE_BUNDLE>>4) & 0x0F), "Refuse Bundle"},
|
|
{((TCP_CONVERGENCE_KEEP_ALIVE>>4) & 0x0F), "Keep Alive"},
|
|
{((TCP_CONVERGENCE_SHUTDOWN>>4) & 0x0F), "Shutdown"},
|
|
{((TCP_CONVERGENCE_LENGTH>>4) & 0x0F), "Length"},
|
|
{0, NULL}
|
|
};
|
|
|
|
/* Refuse-Bundle Reason-Code Flags as per RFC-7242: Section-5.4 */
|
|
static const value_string refuse_bundle_reason_code[] = {
|
|
{TCP_REFUSE_BUNDLE_REASON_UNKNOWN, "Reason for refusal is unknown"},
|
|
{TCP_REFUSE_BUNDLE_REASON_RX_COMPLETE, "Complete Bundle Received"},
|
|
{TCP_REFUSE_BUNDLE_REASON_RX_EXHAUSTED, "Receiver's resources exhausted"},
|
|
{TCP_REFUSE_BUNDLE_REASON_RX_RETRANSMIT, "Receiver expects re-transmission of bundle"},
|
|
{0, NULL}
|
|
};
|
|
|
|
static const fragment_items msg_frag_items = {
|
|
/*Fragment subtrees*/
|
|
&ett_msg_fragment,
|
|
&ett_msg_fragments,
|
|
/*Fragment Fields*/
|
|
&hf_msg_fragments,
|
|
&hf_msg_fragment,
|
|
&hf_msg_fragment_overlap,
|
|
&hf_msg_fragment_overlap_conflicts,
|
|
&hf_msg_fragment_multiple_tails,
|
|
&hf_msg_fragment_too_long_fragment,
|
|
&hf_msg_fragment_error,
|
|
&hf_msg_fragment_count,
|
|
/*Reassembled in field*/
|
|
&hf_msg_reassembled_in,
|
|
/*Reassembled length field*/
|
|
&hf_msg_reassembled_length,
|
|
/* Reassembled data field */
|
|
NULL,
|
|
/*Tag*/
|
|
"Message fragments"
|
|
};
|
|
|
|
static guint
|
|
get_dtn_contact_header_len(packet_info *pinfo _U_, tvbuff_t *tvb,
|
|
int offset, void *data _U_)
|
|
{
|
|
int len, bytecount;
|
|
|
|
/* get length from sdnv */
|
|
len = evaluate_sdnv(tvb, offset+8, &bytecount);
|
|
if (len < 0)
|
|
return 0;
|
|
|
|
return len+bytecount+8;
|
|
}
|
|
|
|
static int
|
|
dissect_dtn_contact_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
|
|
{
|
|
proto_item *ti;
|
|
proto_tree *conv_proto_tree, *conv_tree, *conv_flag_tree;
|
|
int eid_length, sdnv_length;
|
|
int offset = 0;
|
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "TCPCLv3");
|
|
col_clear(pinfo->cinfo,COL_INFO); /* Clear out stuff in the info column */
|
|
col_add_str(pinfo->cinfo, COL_INFO, "Contact Header");
|
|
|
|
ti = proto_tree_add_item(tree, proto_tcp_conv, tvb, offset, -1, ENC_NA);
|
|
conv_proto_tree = proto_item_add_subtree(ti, ett_tcp_conv);
|
|
|
|
conv_tree = proto_tree_add_subtree(conv_proto_tree, tvb, offset, -1, ett_tcp_conv, NULL, "Contact Header");
|
|
|
|
proto_tree_add_item(conv_tree, hf_contact_hdr_magic, tvb, offset, 4, ENC_NA|ENC_ASCII);
|
|
offset += 4;
|
|
proto_tree_add_item(conv_tree, hf_contact_hdr_version, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
offset++;
|
|
|
|
/* Subtree to expand the bits in the Contact Header Flags */
|
|
ti = proto_tree_add_item(conv_tree, hf_contact_hdr_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
conv_flag_tree = proto_item_add_subtree(ti, ett_contact_hdr_flags);
|
|
proto_tree_add_item(conv_flag_tree, hf_contact_hdr_flags_ack_req, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item(conv_flag_tree, hf_contact_hdr_flags_frag_enable, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item(conv_flag_tree, hf_contact_hdr_flags_nak, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
offset++;
|
|
|
|
proto_tree_add_item(conv_tree, hf_contact_hdr_keep_alive, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
/*
|
|
* New format Contact header has length field followed by Bundle Header.
|
|
*/
|
|
expert_field *ei_bundle_sdnv_length;
|
|
eid_length = evaluate_sdnv_ei(tvb, offset, &sdnv_length, &ei_bundle_sdnv_length);
|
|
ti = proto_tree_add_int(tree, hf_contact_hdr_local_eid_length, tvb, offset, sdnv_length, eid_length);
|
|
if (ei_bundle_sdnv_length) {
|
|
expert_add_info(pinfo, ti, ei_bundle_sdnv_length);
|
|
return offset;
|
|
}
|
|
|
|
proto_tree_add_item(conv_tree, hf_contact_hdr_local_eid, tvb, sdnv_length + offset, eid_length, ENC_NA|ENC_ASCII);
|
|
return tvb_captured_length(tvb);
|
|
}
|
|
|
|
static guint
|
|
get_tcpcl_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
|
|
{
|
|
int len, bytecount;
|
|
guint8 conv_hdr = tvb_get_guint8(tvb, offset);
|
|
|
|
switch (conv_hdr & TCP_CONVERGENCE_TYPE_MASK)
|
|
{
|
|
case TCP_CONVERGENCE_DATA_SEGMENT:
|
|
/* get length from sdnv */
|
|
len = evaluate_sdnv(tvb, offset+1, &bytecount);
|
|
if (len < 0)
|
|
return 0;
|
|
|
|
return len+bytecount+1;
|
|
|
|
case TCP_CONVERGENCE_ACK_SEGMENT:
|
|
/* get length from sdnv */
|
|
len = evaluate_sdnv(tvb, offset+1, &bytecount);
|
|
if (len < 0)
|
|
return 0;
|
|
|
|
return bytecount+1;
|
|
|
|
case TCP_CONVERGENCE_KEEP_ALIVE:
|
|
case TCP_CONVERGENCE_REFUSE_BUNDLE:
|
|
/* always 1 byte */
|
|
return 1;
|
|
case TCP_CONVERGENCE_SHUTDOWN:
|
|
len = 1;
|
|
|
|
if (conv_hdr & TCP_CONVERGENCE_SHUTDOWN_REASON) {
|
|
len += 1;
|
|
}
|
|
if (conv_hdr & TCP_CONVERGENCE_SHUTDOWN_DELAY) {
|
|
len += 2;
|
|
}
|
|
|
|
return len;
|
|
|
|
case TCP_CONVERGENCE_LENGTH:
|
|
/* get length from sdnv */
|
|
len = evaluate_sdnv(tvb, offset+1, &bytecount);
|
|
if (len < 0)
|
|
return 0;
|
|
return bytecount+1;
|
|
|
|
}
|
|
|
|
/* This probably isn't a TCPCL/Bundle packet, so just stop dissection */
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
dissect_tcpcl_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
|
|
{
|
|
guint8 conv_hdr;
|
|
guint8 refuse_bundle_hdr;
|
|
int offset = 0;
|
|
int sdnv_length, segment_length, convergence_hdr_size;
|
|
proto_item *ci, *sub_item;
|
|
proto_tree *conv_proto_tree, *conv_tree, *sub_tree;
|
|
fragment_head *frag_msg;
|
|
tvbuff_t *new_tvb;
|
|
gboolean more_frags;
|
|
int processed_length = 0;
|
|
const gchar* col_text;
|
|
gboolean bundle_in_col_info;
|
|
|
|
static guint32 frag_id = 0;
|
|
static guint32 last_frame = 0;
|
|
static int last_raw_offset = 0;
|
|
|
|
if (last_frame != pinfo->fd->num || tvb_raw_offset(tvb) < last_raw_offset)
|
|
frag_id = 0;
|
|
last_frame = pinfo->fd->num;
|
|
last_raw_offset = tvb_raw_offset(tvb);
|
|
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "TCPCL");
|
|
col_clear(pinfo->cinfo,COL_INFO); /* Clear out stuff in the info column */
|
|
|
|
col_text = col_get_text(pinfo->cinfo, COL_INFO);
|
|
bundle_in_col_info = (col_text && strstr(col_text, " > "));
|
|
|
|
ci = proto_tree_add_item(tree, proto_tcp_conv, tvb, offset, -1, ENC_NA);
|
|
conv_proto_tree = proto_item_add_subtree(ci, ett_tcp_conv);
|
|
|
|
conv_tree = proto_tree_add_subtree(conv_proto_tree, tvb, 0, -1, ett_tcp_conv_hdr, NULL, "TCP Convergence Header");
|
|
|
|
conv_hdr = tvb_get_guint8(tvb, offset);
|
|
proto_tree_add_item(conv_tree, hf_tcp_convergence_pkt_type, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
col_add_str(pinfo->cinfo, COL_INFO, val_to_str_const((conv_hdr>>4)&0xF, packet_type_vals, "Unknown"));
|
|
|
|
switch (conv_hdr & TCP_CONVERGENCE_TYPE_MASK)
|
|
{
|
|
case TCP_CONVERGENCE_DATA_SEGMENT:
|
|
sub_item = proto_tree_add_item(conv_tree, hf_tcp_convergence_data_procflags, tvb,
|
|
offset, 1, ENC_BIG_ENDIAN);
|
|
sub_tree = proto_item_add_subtree(sub_item, ett_conv_flags);
|
|
proto_tree_add_item(sub_tree, hf_tcp_convergence_data_procflags_start,
|
|
tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item(sub_tree, hf_tcp_convergence_data_procflags_end,
|
|
tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
|
|
/* Only Start and End flags (bits 0 & 1) are valid in Data Segment */
|
|
if ((conv_hdr & ~(TCP_CONVERGENCE_TYPE_MASK | TCP_CONVERGENCE_DATA_FLAGS)) != 0) {
|
|
expert_add_info(pinfo, sub_item, &ei_tcp_convergence_data_flags);
|
|
}
|
|
|
|
segment_length = evaluate_sdnv(tvb, 1, &sdnv_length);
|
|
sub_item = proto_tree_add_int(conv_tree, hf_tcp_convergence_data_segment_length, tvb, 1, sdnv_length, segment_length);
|
|
if (segment_length < 0) {
|
|
expert_add_info(pinfo, sub_item, &ei_tcp_convergence_segment_length);
|
|
return 1;
|
|
}
|
|
|
|
convergence_hdr_size = sdnv_length + 1;
|
|
|
|
/*
|
|
* 1/11/2006 - If I got here, I should have a complete convergence layer
|
|
* "segment" beginning at frame_offset. However that might not be a
|
|
* complete bundle. Or there might be a complete bundle plus one or more
|
|
* additional convergence layer headers.
|
|
*/
|
|
|
|
new_tvb = NULL;
|
|
sub_tree = NULL;
|
|
if ((conv_hdr & TCP_CONVERGENCE_DATA_END_FLAG) == TCP_CONVERGENCE_DATA_END_FLAG) {
|
|
more_frags = FALSE;
|
|
}
|
|
else {
|
|
more_frags = TRUE;
|
|
}
|
|
|
|
frag_msg = fragment_add_seq_next(&msg_reassembly_table,
|
|
tvb, offset + convergence_hdr_size,
|
|
pinfo, frag_id, data,
|
|
segment_length, more_frags);
|
|
|
|
if (!more_frags) ++frag_id;
|
|
|
|
processed_length = convergence_hdr_size + segment_length;
|
|
|
|
if (frag_msg && !more_frags) {
|
|
|
|
int save_fd_head_layer = frag_msg->reas_in_layer_num;
|
|
frag_msg->reas_in_layer_num = pinfo->curr_layer_num;
|
|
|
|
new_tvb = process_reassembled_data(tvb, offset + convergence_hdr_size,
|
|
pinfo, "Reassembled DTN", frag_msg,
|
|
&msg_frag_items, NULL,
|
|
proto_tree_get_parent_tree(tree)
|
|
);
|
|
|
|
frag_msg->reas_in_layer_num = save_fd_head_layer;
|
|
}
|
|
|
|
if (new_tvb) {
|
|
if (0 == call_dissector_with_data(bundle_handle, new_tvb, pinfo, sub_tree, data)) {
|
|
/*Couldn't parse bundle, treat as raw data */
|
|
call_data_dissector(new_tvb, pinfo, sub_tree);
|
|
return tvb_captured_length(tvb);
|
|
}
|
|
}
|
|
else {
|
|
|
|
/*
|
|
* If there are 2 segments, the second of which is very short, this
|
|
* gets displayed instead of the usual Source EID/Destination EID in
|
|
* the Bundle Dissection frame. If these statements are left out entirely,
|
|
* nothing is displayed, i.e., there seems to be no way to get the
|
|
* Source/Destination in the 2-segment case. I'll leave it in because I
|
|
* think it is informative in the multi-segment case although confusing in the
|
|
* 2-segment case.
|
|
*/
|
|
col_add_str(pinfo->cinfo, COL_INFO, "[Bundle TCPCL Segment]");
|
|
}
|
|
break;
|
|
case TCP_CONVERGENCE_ACK_SEGMENT:
|
|
if (bundle_in_col_info) {
|
|
if (!strstr(col_text, ", TCPL ACK")) {
|
|
col_add_str(pinfo->cinfo, COL_INFO, ", TCPL ACK Segment(s)");
|
|
}
|
|
} else {
|
|
col_set_str(pinfo->cinfo, COL_INFO, "TCPL ACK Segment(s)");
|
|
}
|
|
segment_length = evaluate_sdnv(tvb, offset+1, &sdnv_length);
|
|
sub_item = proto_tree_add_int(conv_tree, hf_tcp_convergence_ack_length, tvb, offset+1, sdnv_length, segment_length);
|
|
if (segment_length < 0) {
|
|
expert_add_info(pinfo, sub_item, &ei_tcp_convergence_ack_length);
|
|
processed_length = tvb_captured_length(tvb);
|
|
} else {
|
|
processed_length = sdnv_length + 1;
|
|
}
|
|
break;
|
|
case TCP_CONVERGENCE_KEEP_ALIVE:
|
|
if (bundle_in_col_info) {
|
|
if (!strstr(col_text, ", TCPL KEEPALIVE")) {
|
|
col_add_str(pinfo->cinfo, COL_INFO, ", TCPL KEEPALIVE Segment");
|
|
}
|
|
} else {
|
|
col_set_str(pinfo->cinfo, COL_INFO, "TCPL KEEPALIVE Segment");
|
|
}
|
|
/*No valid flags in Keep Alive*/
|
|
processed_length = 1;
|
|
break;
|
|
|
|
case TCP_CONVERGENCE_SHUTDOWN:
|
|
if (bundle_in_col_info) {
|
|
if (!strstr(col_text, ", TCPL SHUTDOWN")) {
|
|
col_add_str(pinfo->cinfo, COL_INFO, ", TCPL SHUTDOWN Segment");
|
|
}
|
|
} else {
|
|
col_set_str(pinfo->cinfo, COL_INFO, "TCPL SHUTDOWN Segment");
|
|
}
|
|
/* Add tree for Shutdown Flags */
|
|
sub_item = proto_tree_add_item(conv_tree, hf_tcp_convergence_shutdown_flags, tvb,
|
|
offset, 1, ENC_BIG_ENDIAN);
|
|
sub_tree = proto_item_add_subtree(sub_item, ett_shutdown_flags);
|
|
|
|
proto_tree_add_item(sub_tree, hf_tcp_convergence_shutdown_flags_reason,
|
|
tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item(sub_tree, hf_tcp_convergence_shutdown_flags_delay,
|
|
tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
|
|
offset += 1;
|
|
if (conv_hdr & TCP_CONVERGENCE_SHUTDOWN_REASON) {
|
|
proto_tree_add_item(conv_tree,
|
|
hf_tcp_convergence_shutdown_reason, tvb,
|
|
offset, 1, ENC_BIG_ENDIAN);
|
|
offset += 1;
|
|
}
|
|
if (conv_hdr & TCP_CONVERGENCE_SHUTDOWN_DELAY) {
|
|
proto_tree_add_item(conv_tree,
|
|
hf_tcp_convergence_shutdown_delay, tvb,
|
|
offset, 2, ENC_BIG_ENDIAN);
|
|
}
|
|
break;
|
|
case TCP_CONVERGENCE_REFUSE_BUNDLE:
|
|
if (bundle_in_col_info) {
|
|
if (!strstr(col_text, ", TCPL REFUSE")) {
|
|
col_add_str(pinfo->cinfo, COL_INFO, ", TCPL REFUSE_BUNDLE Segment");
|
|
}
|
|
} else {
|
|
col_set_str(pinfo->cinfo, COL_INFO, "TCPL REFUSE_BUNDLE Segment");
|
|
}
|
|
|
|
refuse_bundle_hdr = tvb_get_guint8(tvb, offset);
|
|
proto_tree_add_item(conv_tree, hf_dtn_refuse_bundle_reason_code, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
col_add_str(pinfo->cinfo, COL_INFO, val_to_str_const((refuse_bundle_hdr>>4)&0xF, refuse_bundle_reason_code, "Unknown"));
|
|
|
|
/*No valid flags*/
|
|
processed_length = tvb_captured_length(tvb);
|
|
break;
|
|
}
|
|
|
|
return processed_length;
|
|
}
|
|
|
|
static int
|
|
dissect_tcpcl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|
{
|
|
guint8 conv_hdr;
|
|
int offset, bytecount;
|
|
int processed_length;
|
|
|
|
/* Make sure we have a convergence header byte */
|
|
if (!tvb_bytes_exist(tvb, 0, 1))
|
|
return 0;
|
|
|
|
conv_hdr = tvb_get_guint8(tvb, 0);
|
|
switch (conv_hdr & TCP_CONVERGENCE_TYPE_MASK)
|
|
{
|
|
case TCP_CONVERGENCE_DATA_SEGMENT:
|
|
case TCP_CONVERGENCE_ACK_SEGMENT:
|
|
/* ensure sdnv */
|
|
offset = 1;
|
|
bytecount = 1;
|
|
|
|
if (!tvb_bytes_exist(tvb, offset, 1)) {
|
|
pinfo->desegment_offset = 0;
|
|
pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
|
|
return 0;
|
|
}
|
|
|
|
while (tvb_get_guint8(tvb, offset) & ~SDNV_MASK) {
|
|
if (bytecount > (int)sizeof(int)) {
|
|
/* invalid length field */
|
|
return 0;
|
|
}
|
|
|
|
bytecount++;
|
|
offset++;
|
|
|
|
if (!tvb_bytes_exist(tvb, offset, 1)) {
|
|
pinfo->desegment_offset = 0;
|
|
pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
case TCP_CONVERGENCE_KEEP_ALIVE:
|
|
case TCP_CONVERGENCE_REFUSE_BUNDLE:
|
|
/* always 1 byte */
|
|
break;
|
|
case TCP_CONVERGENCE_SHUTDOWN:
|
|
if ((conv_hdr &
|
|
~(TCP_CONVERGENCE_TYPE_MASK | TCP_CONVERGENCE_SHUTDOWN_FLAGS)) != 0) {
|
|
/* Not for us */
|
|
return 0;
|
|
}
|
|
break;
|
|
default:
|
|
if (conv_hdr == (guint8)magic[0]) {
|
|
if (!tvb_bytes_exist(tvb, 0, 4) || tvb_memeql(tvb, 0, magic, 4)) {
|
|
/* Not for us */
|
|
return 0;
|
|
}
|
|
|
|
tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 8, get_dtn_contact_header_len, dissect_dtn_contact_header, data);
|
|
return tvb_captured_length(tvb);
|
|
}
|
|
|
|
/* Not for us */
|
|
return 0;
|
|
};
|
|
|
|
processed_length = get_tcpcl_pdu_len(pinfo, tvb, 0, data);
|
|
|
|
tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 1, get_tcpcl_pdu_len, dissect_tcpcl_pdu, data);
|
|
|
|
return processed_length;
|
|
}
|
|
|
|
|
|
void
|
|
proto_register_tcpclv3(void)
|
|
{
|
|
|
|
static hf_register_info hf_tcpcl[] = {
|
|
{&hf_tcp_convergence_pkt_type,
|
|
{"Pkt Type", "tcpcl.pkt_type",
|
|
FT_UINT8, BASE_DEC, VALS(packet_type_vals), 0xF0, NULL, HFILL}
|
|
},
|
|
{&hf_dtn_refuse_bundle_reason_code,
|
|
{"Reason-Code", "tcpcl.refuse.reason_code",
|
|
FT_UINT8, BASE_DEC, VALS(refuse_bundle_reason_code), 0x0F, NULL, HFILL}
|
|
},
|
|
{&hf_tcp_convergence_data_procflags,
|
|
{"TCP Convergence Data Flags", "tcpcl.data.proc.flag",
|
|
FT_UINT8, BASE_HEX, NULL, TCP_CONVERGENCE_DATA_FLAGS, NULL, HFILL}
|
|
},
|
|
{&hf_tcp_convergence_data_procflags_start,
|
|
{"Segment contains start of bundle", "tcpcl.data.proc.start",
|
|
FT_BOOLEAN, 8, NULL, TCP_CONVERGENCE_DATA_START_FLAG, NULL, HFILL}
|
|
},
|
|
{&hf_tcp_convergence_data_procflags_end,
|
|
{"Segment contains end of Bundle", "tcpcl.data.proc.end",
|
|
FT_BOOLEAN, 8, NULL, TCP_CONVERGENCE_DATA_END_FLAG, NULL, HFILL}
|
|
},
|
|
{&hf_tcp_convergence_data_segment_length,
|
|
{"Segment Length", "tcpcl.data.length",
|
|
FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_tcp_convergence_shutdown_flags,
|
|
{"TCP Convergence Shutdown Flags", "tcpcl.shutdown.flags",
|
|
FT_UINT8, BASE_HEX, NULL, TCP_CONVERGENCE_SHUTDOWN_FLAGS, NULL, HFILL}
|
|
},
|
|
{&hf_tcp_convergence_shutdown_flags_reason,
|
|
{"Shutdown includes Reason Code", "tcpcl.shutdown.reason.flag",
|
|
FT_BOOLEAN, 8, NULL, TCP_CONVERGENCE_SHUTDOWN_REASON, NULL, HFILL}
|
|
},
|
|
{&hf_tcp_convergence_shutdown_flags_delay,
|
|
{"Shutdown includes Reconnection Delay", "tcpcl.shutdown.delay.flag",
|
|
FT_BOOLEAN, 8, NULL, TCP_CONVERGENCE_SHUTDOWN_DELAY, NULL, HFILL}
|
|
},
|
|
{&hf_tcp_convergence_shutdown_reason,
|
|
{"Shutdown Reason Code", "tcpcl.shutdown.reason",
|
|
FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_tcp_convergence_shutdown_delay,
|
|
{"Shutdown Reconnection Delay", "tcpcl.shutdown.delay",
|
|
FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_tcp_convergence_ack_length,
|
|
{"Ack Length", "tcpcl.ack.length",
|
|
FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_contact_hdr_version,
|
|
{"Version", "tcpcl.contact_hdr.version",
|
|
FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_contact_hdr_flags,
|
|
{"Flags", "tcpcl.contact_hdr.flags",
|
|
FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_contact_hdr_flags_ack_req,
|
|
{"Bundle Acks Requested", "tcpcl.contact_hdr.flags.ackreq",
|
|
FT_BOOLEAN, 8, NULL, TCP_CONV_BUNDLE_ACK_FLAG, NULL, HFILL}
|
|
},
|
|
{&hf_contact_hdr_flags_frag_enable,
|
|
{"Reactive Fragmentation Enabled", "tcpcl.contact_hdr.flags.fragen",
|
|
FT_BOOLEAN, 8, NULL, TCP_CONV_REACTIVE_FRAG_FLAG, NULL, HFILL}
|
|
},
|
|
{&hf_contact_hdr_flags_nak,
|
|
{"Support Negative Acknowledgements", "tcpcl.contact_hdr.flags.nak",
|
|
FT_BOOLEAN, 8, NULL, TCP_CONV_CONNECTOR_RCVR_FLAG, NULL, HFILL}
|
|
},
|
|
{&hf_contact_hdr_keep_alive,
|
|
{"Keep Alive", "tcpcl.contact_hdr.keep_alive",
|
|
FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_contact_hdr_magic,
|
|
{"Magic", "tcpcl.contact_hdr.magic",
|
|
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_contact_hdr_local_eid,
|
|
{"Local EID", "tcpcl.contact_hdr.local_eid",
|
|
FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_contact_hdr_local_eid_length,
|
|
{"Local EID Length", "tcpcl.contact_hdr.local_eid_length",
|
|
FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
|
|
{&hf_msg_fragments,
|
|
{"Message Fragments", "tcpcl.msg.fragments",
|
|
FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_msg_fragment,
|
|
{"Message Fragment", "tcpcl.msg.fragment",
|
|
FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_msg_fragment_overlap,
|
|
{"Message fragment overlap", "tcpcl.msg.fragment.overlap",
|
|
FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_msg_fragment_overlap_conflicts,
|
|
{"Message fragment overlapping with conflicting data",
|
|
"tcpcl.msg.fragment.overlap.conflicts",
|
|
FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_msg_fragment_multiple_tails,
|
|
{"Message has multiple tails", "tcpcl.msg.fragment.multiple_tails",
|
|
FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_msg_fragment_too_long_fragment,
|
|
{"Message fragment too long", "tcpcl.msg.fragment.too_long_fragment",
|
|
FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_msg_fragment_error,
|
|
{"Message defragmentation error", "tcpcl.msg.fragment.error",
|
|
FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_msg_fragment_count,
|
|
{"Message fragment count", "tcpcl.msg.fragment.count",
|
|
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_msg_reassembled_in,
|
|
{"Reassembled in", "tcpcl.msg.reassembled.in",
|
|
FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
{&hf_msg_reassembled_length,
|
|
{"Reassembled DTN length", "tcpcl.msg.reassembled.length",
|
|
FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}
|
|
},
|
|
};
|
|
|
|
static gint *ett_tcpcl[] = {
|
|
&ett_tcp_conv,
|
|
&ett_tcp_conv_hdr,
|
|
&ett_conv_flags,
|
|
&ett_contact_hdr_flags,
|
|
&ett_shutdown_flags,
|
|
&ett_msg_fragment,
|
|
&ett_msg_fragments,
|
|
};
|
|
|
|
static ei_register_info ei_tcpcl[] = {
|
|
{ &ei_tcp_convergence_data_flags,
|
|
{ "tcpcl.data.flags.invalid", PI_PROTOCOL, PI_WARN, "Invalid TCP CL Data Segment Flags", EXPFILL }
|
|
},
|
|
{ &ei_tcp_convergence_segment_length,
|
|
{ "tcpcl.data.length.invalid", PI_PROTOCOL, PI_ERROR, "Invalid Data Length", EXPFILL }
|
|
},
|
|
{ &ei_tcp_convergence_ack_length,
|
|
{ "tcpcl.ack.length.error", PI_PROTOCOL, PI_WARN, "Ack Length: Error", EXPFILL }
|
|
},
|
|
};
|
|
|
|
expert_module_t *expert_tcpcl;
|
|
|
|
proto_tcp_conv = proto_register_protocol ("DTN TCP Convergence Layer Protocol", "TCPCL", "tcpcl");
|
|
|
|
proto_register_field_array(proto_tcp_conv, hf_tcpcl, array_length(hf_tcpcl));
|
|
proto_register_subtree_array(ett_tcpcl, array_length(ett_tcpcl));
|
|
expert_tcpcl = expert_register_protocol(proto_tcp_conv);
|
|
expert_register_field_array(expert_tcpcl, ei_tcpcl, array_length(ei_tcpcl));
|
|
|
|
reassembly_table_register(&msg_reassembly_table,
|
|
&addresses_reassembly_table_functions);
|
|
|
|
}
|
|
|
|
void
|
|
proto_reg_handoff_tcpclv3(void)
|
|
{
|
|
dissector_handle_t tcpcl_handle;
|
|
|
|
bundle_handle = find_dissector("bundle");
|
|
|
|
tcpcl_handle = create_dissector_handle(dissect_tcpcl, proto_tcp_conv);
|
|
dissector_add_uint_with_preference("tcp.port", BUNDLE_PORT, tcpcl_handle);
|
|
}
|
|
|
|
/*
|
|
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
|
*
|
|
* Local variables:
|
|
* c-basic-offset: 4
|
|
* tab-width: 8
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*
|
|
* vi: set shiftwidth=4 tabstop=8 expandtab:
|
|
* :indentSize=4:tabSize=8:noTabs=true:
|
|
*/
|