diff --git a/debian/libwiretap0.symbols b/debian/libwiretap0.symbols index 45db4ab48c..f86acc5995 100644 --- a/debian/libwiretap0.symbols +++ b/debian/libwiretap0.symbols @@ -28,6 +28,7 @@ libwiretap.so.0 libwiretap0 #MINVER# wtap_block_add_if_filter_option@Base 3.5.0 wtap_block_add_ipv4_option@Base 2.1.2 wtap_block_add_ipv6_option@Base 2.1.2 + wtap_block_add_nflx_custom_option@Base 3.5.0 wtap_block_add_string_option@Base 2.1.2 wtap_block_add_string_option_format@Base 2.1.2 wtap_block_add_uint32_option@Base 3.5.0 @@ -43,6 +44,7 @@ libwiretap.so.0 libwiretap0 #MINVER# wtap_block_get_ipv4_option_value@Base 2.1.2 wtap_block_get_ipv6_option_value@Base 2.1.2 wtap_block_get_mandatory_data@Base 2.1.2 + wtap_block_get_nflx_custom_option@Base 3.5.0 wtap_block_get_nth_bytes_option_value@Base 3.5.0 wtap_block_get_nth_string_option_value@Base 2.1.2 wtap_block_get_options_size_padded@Base 3.5.0 diff --git a/epan/dissectors/CMakeLists.txt b/epan/dissectors/CMakeLists.txt index f9c4ac04fa..09afb57821 100644 --- a/epan/dissectors/CMakeLists.txt +++ b/epan/dissectors/CMakeLists.txt @@ -734,6 +734,7 @@ set(DISSECTOR_SRC ${CMAKE_CURRENT_SOURCE_DIR}/packet-banana.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-bat.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-batadv.c + ${CMAKE_CURRENT_SOURCE_DIR}/packet-bblog.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-bctp.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-beep.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-bencode.c diff --git a/epan/dissectors/packet-bblog.c b/epan/dissectors/packet-bblog.c new file mode 100644 index 0000000000..267a2a738f --- /dev/null +++ b/epan/dissectors/packet-bblog.c @@ -0,0 +1,419 @@ +/* packet-bblog.c + * Routines for Black Box Log dissection + * Copyright 2021 Michael Tuexen + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + +#include "config.h" + +#include + +void proto_register_bblog_event(void); +void proto_reg_handoff_bblog(void); + +static int proto_bblog = -1; + +static int hf_ticks = -1; +static int hf_serial_nr = -1; +static int hf_stack_id = -1; +static int hf_event_id = -1; +static int hf_event_flags = -1; +static int hf_event_flags_rxbuf = -1; +static int hf_event_flags_txbuf = -1; +static int hf_event_flags_hdr = -1; +static int hf_event_flags_verbose = -1; +static int hf_event_flags_stack = -1; +static int hf_errno = -1; +static int hf_rxb_acc = -1; +static int hf_rxb_ccc = -1; +static int hf_rxb_spare = -1; +static int hf_txb_acc = -1; +static int hf_txb_ccc = -1; +static int hf_txb_spare = -1; +static int hf_state = -1; +static int hf_starttime = -1; +static int hf_iss = -1; +static int hf_flags = -1; +static int hf_snd_una = -1; +static int hf_snd_max = -1; +static int hf_snd_cwnd = -1; +static int hf_snd_nxt = -1; +static int hf_snd_recover = -1; +static int hf_snd_wnd = -1; +static int hf_snd_ssthresh = -1; +static int hf_srtt = -1; +static int hf_rttvar = -1; +static int hf_rcv_up = -1; +static int hf_rcv_adv = -1; +static int hf_flags2 = -1; +static int hf_rcv_nxt = -1; +static int hf_rcv_wnd = -1; +static int hf_dupacks = -1; +static int hf_seg_qlen = -1; +static int hf_snd_num_holes = -1; +static int hf_flex_1 = -1; +static int hf_flex_2 = -1; +static int hf_first_byte_in = -1; +static int hf_first_byte_out = -1; +static int hf_snd_scale = -1; +static int hf_rcv_scale = -1; +static int hf_pad_1 = -1; +static int hf_pad_2 = -1; +static int hf_pad_3 = -1; +static int hf_payload_len = -1; + +static gint ett_bblog = -1; +static gint ett_bblog_flags = -1; + +#define TCP_LOG_IN 1 +#define TCP_LOG_OUT 2 +#define TCP_LOG_RTO 3 +#define TCP_LOG_SB_WAKE 4 +#define TCP_LOG_BAD_RETRAN 5 +#define TCP_LOG_PRR 6 +#define TCP_LOG_REORDER 7 +#define TCP_LOG_HPTS 8 +#define BBR_LOG_BBRUPD 9 +#define BBR_LOG_BBRSND 10 +#define BBR_LOG_ACKCLEAR 11 +#define BBR_LOG_INQUEUE 12 +#define BBR_LOG_TIMERSTAR 13 +#define BBR_LOG_TIMERCANC 14 +#define BBR_LOG_ENTREC 15 +#define BBR_LOG_EXITREC 16 +#define BBR_LOG_CWND 17 +#define BBR_LOG_BWSAMP 18 +#define BBR_LOG_MSGSIZE 19 +#define BBR_LOG_BBRRTT 20 +#define BBR_LOG_JUSTRET 21 +#define BBR_LOG_STATE 22 +#define BBR_LOG_PKT_EPOCH 23 +#define BBR_LOG_PERSIST 24 +#define TCP_LOG_FLOWEND 25 +#define BBR_LOG_RTO 26 +#define BBR_LOG_DOSEG_DONE 27 +#define BBR_LOG_EXIT_GAIN 28 +#define BBR_LOG_THRESH_CALC 29 +#define TCP_LOG_MAPCHG 30 +#define TCP_LOG_USERSEND 31 +#define BBR_RSM_CLEARED 32 +#define BBR_LOG_STATE_TARGET 33 +#define BBR_LOG_TIME_EPOCH 34 +#define BBR_LOG_TO_PROCESS 35 +#define BBR_LOG_BBRTSO 36 +#define BBR_LOG_HPTSDIAG 37 +#define BBR_LOG_LOWGAIN 38 +#define BBR_LOG_PROGRESS 39 +#define TCP_LOG_SOCKET_OPT 40 +#define BBR_LOG_TIMERPREP 41 +#define BBR_LOG_ENOBUF_JMP 42 +#define BBR_LOG_HPTSI_CALC 43 +#define BBR_LOG_RTT_SHRINKS 44 +#define BBR_LOG_BW_RED_EV 45 +#define BBR_LOG_REDUCE 46 +#define TCP_LOG_RTT 47 +#define BBR_LOG_SETTINGS_CHG 48 +#define BBR_LOG_SRTT_GAIN_EVENT 49 +#define TCP_LOG_REASS 50 +#define TCP_HDWR_TLS 51 +#define BBR_LOG_HDWR_PACE 52 +#define BBR_LOG_TSTMP_VAL 53 +#define TCP_LOG_CONNEND 54 +#define TCP_LOG_LRO 55 +#define TCP_SACK_FILTER_RES 56 +#define TCP_SAD_DETECTION 57 +#define TCP_TIMELY_WORK 58 +#define TCP_LOG_USER_EVENT 59 +#define TCP_LOG_SENDFILE 60 +#define TCP_LOG_HTTP_T 61 +#define TCP_LOG_ACCOUNTING 62 +#define TCP_LOG_FSB 63 + + +static const value_string event_identifier_values[] = { + { TCP_LOG_IN, "Incoming packet" }, + { TCP_LOG_OUT, "Transmit (without other event)" }, + { TCP_LOG_RTO, "Retransmit timeout" }, + { TCP_LOG_SB_WAKE, "Awaken socket buffer" }, + { TCP_LOG_BAD_RETRAN, "Detected bad retransmission" }, + { TCP_LOG_PRR, "Doing PRR" }, + { TCP_LOG_REORDER, "Detected reorder" }, + { TCP_LOG_HPTS, "Hpts sending a packet" }, + { BBR_LOG_BBRUPD, "We updated BBR info" }, + { BBR_LOG_BBRSND, "We did a slot calculation and sending is done" }, + { BBR_LOG_ACKCLEAR, "A ack clears all outstanding" }, + { BBR_LOG_INQUEUE, "The tcb had a packet input to it" }, + { BBR_LOG_TIMERSTAR, "Start a timer" }, + { BBR_LOG_TIMERCANC, "Cancel a timer" }, + { BBR_LOG_ENTREC, "Entered recovery" }, + { BBR_LOG_EXITREC, "Exited recovery" }, + { BBR_LOG_CWND, "Cwnd change" }, + { BBR_LOG_BWSAMP, "LT B/W sample has been made" }, + { BBR_LOG_MSGSIZE, "We received a EMSGSIZE error" }, + { BBR_LOG_BBRRTT, "BBR RTT is updated" }, + { BBR_LOG_JUSTRET, "We just returned out of output" }, + { BBR_LOG_STATE, "A BBR state change occured" }, + { BBR_LOG_PKT_EPOCH, "A BBR packet epoch occured" }, + { BBR_LOG_PERSIST, "BBR changed to/from a persists" }, + { TCP_LOG_FLOWEND, "End of a flow" }, + { BBR_LOG_RTO, "BBR's timeout includes BBR info" }, + { BBR_LOG_DOSEG_DONE, "hpts do_segment completes" }, + { BBR_LOG_EXIT_GAIN, "hpts do_segment completes" }, + { BBR_LOG_THRESH_CALC, "Doing threshold calculation" }, + { TCP_LOG_MAPCHG, "Map Changes to the sendmap" }, + { TCP_LOG_USERSEND, "User level sends data" }, + { BBR_RSM_CLEARED, "RSM cleared of ACK flags" }, + { BBR_LOG_STATE_TARGET, "Log of target at state" }, + { BBR_LOG_TIME_EPOCH, "A timed based Epoch occured" }, + { BBR_LOG_TO_PROCESS, "A to was processed" }, + { BBR_LOG_BBRTSO, "TSO update" }, + { BBR_LOG_HPTSDIAG, "Hpts diag insert" }, + { BBR_LOG_LOWGAIN, "Low gain accounting" }, + { BBR_LOG_PROGRESS, "Progress timer event" }, + { TCP_LOG_SOCKET_OPT, "A socket option is set" }, + { BBR_LOG_TIMERPREP, "A BBR var to debug out TLP issues" }, + { BBR_LOG_ENOBUF_JMP, "We had a enobuf jump" }, + { BBR_LOG_HPTSI_CALC, "calc the hptsi time" }, + { BBR_LOG_RTT_SHRINKS, "We had a log reduction of rttProp" }, + { BBR_LOG_BW_RED_EV, "B/W reduction events" }, + { BBR_LOG_REDUCE, "old bbr log reduce for 4.1 and earlier" }, + { TCP_LOG_RTT, "A rtt (in useconds) is being sampled and applied to the srtt algo" }, + { BBR_LOG_SETTINGS_CHG, "Settings changed for loss response 48" }, + { BBR_LOG_SRTT_GAIN_EVENT, "SRTT gaining -- now not used" }, + { TCP_LOG_REASS, "Reassembly buffer logging" }, + { TCP_HDWR_TLS, "TCP Hardware TLS logs" }, + { BBR_LOG_HDWR_PACE, "TCP Hardware pacing log" }, + { BBR_LOG_TSTMP_VAL, "Temp debug timestamp validation" }, + { TCP_LOG_CONNEND, "End of connection" }, + { TCP_LOG_LRO, "LRO entry" }, + { TCP_SACK_FILTER_RES, "Results of SACK Filter" }, + { TCP_SAD_DETECTION, "Sack Attack Detection" }, + { TCP_TIMELY_WORK, "Logs regarding Timely CC tweaks" }, + { TCP_LOG_USER_EVENT, "User space event data" }, + { TCP_LOG_SENDFILE, "sendfile() logging for TCP connections" }, + { TCP_LOG_HTTP_T, "logging of http request tracking" }, + { TCP_LOG_ACCOUNTING, "Log of TCP Accounting data" }, + { TCP_LOG_FSB, "FSB information 63" }, + { 0, NULL } }; + +static const value_string tcp_state_values[] = { + { 0, "CLOSED" }, + { 1, "LISTEN" }, + { 2, "SYN SENT" }, + { 3, "SYN RECEIVED" }, + { 4, "ESTABLISHED" }, + { 5, "CLOSE WAIT" }, + { 6, "FIN WAIT 1" }, + { 7, "CLOSING" }, + { 8, "LAST ACK" }, + { 9, "FIN WAIT 2" }, + { 10, "TIME WAIT" }, + { 0, NULL } }; + +#define EVENT_FLAG_RXBUF 0x0001 +#define EVENT_FLAG_TXBUF 0x0002 +#define EVENT_FLAG_HDR 0x0004 +#define EVENT_FLAG_VERBOSE 0x0008 +#define EVENT_FLAG_STACKINFO 0x0010 + +static const true_false_string event_flags_rxbuf = { + "Receive buffer information available", + "Receive buffer information not available" +}; + +static const true_false_string event_flags_txbuf = { + "Send buffer information available", + "Send buffer information not available" +}; + +static const true_false_string event_flags_hdr = { + "TCP header available", + "TCP header not available" +}; + +static const true_false_string event_flags_verbose = { + "Additional information available", + "Additional information not available" +}; + +static const true_false_string event_flags_stack = { + "Stack specific information available", + "Stack specific information not available" +}; + +#define SND_SCALE_MASK 0xf0 +#define RCV_SCALE_MASK 0x0f + +/* + * The structures used here are defined in + * https://cgit.freebsd.org/src/tree/sys/netinet/tcp_log_buf.h + */ + +static int +dissect_bblog(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + proto_item *bblog_item, *event_flags_item; + proto_tree *bblog_tree, *event_flags_tree; + guint16 event_flags; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "BBLog"); + col_append_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str_const(tvb_get_guint8(tvb, 25), event_identifier_values, "Unknown")); + + bblog_item = proto_tree_add_item(tree, proto_bblog, tvb, 0, -1, ENC_NA); + bblog_tree = proto_item_add_subtree(bblog_item, ett_bblog); + + proto_tree_add_item(bblog_tree, hf_ticks, tvb, 16, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_serial_nr, tvb, 20, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_stack_id, tvb, 24, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_event_id, tvb, 25, 1, ENC_LITTLE_ENDIAN); + + event_flags = tvb_get_letohs(tvb, 26); + event_flags_item = proto_tree_add_item(bblog_tree, hf_event_flags, tvb, 26, 2, ENC_LITTLE_ENDIAN); + event_flags_tree = proto_item_add_subtree(event_flags_item, ett_bblog_flags); + proto_tree_add_item(event_flags_tree, hf_event_flags_rxbuf, tvb, 26, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(event_flags_tree, hf_event_flags_txbuf, tvb, 26, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(event_flags_tree, hf_event_flags_hdr, tvb, 26, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(event_flags_tree, hf_event_flags_verbose, tvb, 26, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(event_flags_tree, hf_event_flags_stack, tvb, 26, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_errno, tvb, 28, 4, ENC_LITTLE_ENDIAN); + if (event_flags & EVENT_FLAG_RXBUF) { + proto_tree_add_item(bblog_tree, hf_rxb_acc, tvb, 32, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_rxb_ccc, tvb, 36, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_rxb_spare, tvb, 40, 4, ENC_LITTLE_ENDIAN); + } + if (event_flags & EVENT_FLAG_TXBUF) { + proto_tree_add_item(bblog_tree, hf_txb_acc, tvb, 44, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_txb_ccc, tvb, 48, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_txb_spare, tvb, 52, 4, ENC_LITTLE_ENDIAN); + } + proto_tree_add_item(bblog_tree, hf_state, tvb, 56, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_starttime, tvb, 60, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_iss, tvb, 64, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_flags, tvb, 68, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_snd_una, tvb, 72, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_snd_max, tvb, 76, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_snd_cwnd, tvb, 80, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_snd_nxt, tvb, 84, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_snd_recover, tvb, 88, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_snd_wnd, tvb, 92, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_snd_ssthresh, tvb, 96, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_srtt, tvb, 100, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_rttvar, tvb, 104, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_rcv_up, tvb, 108, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_rcv_adv, tvb, 112, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_flags2, tvb, 116, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_rcv_nxt, tvb, 120, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_rcv_wnd, tvb, 124, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_dupacks, tvb, 128, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_seg_qlen, tvb, 132, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_snd_num_holes, tvb, 136, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_flex_1, tvb, 140, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_flex_2, tvb, 144, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_first_byte_in, tvb, 148, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_first_byte_out, tvb, 152, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_snd_scale, tvb, 156, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_rcv_scale, tvb, 156, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_pad_1, tvb, 157, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_pad_2, tvb, 158, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(bblog_tree, hf_pad_3, tvb, 159, 1, ENC_LITTLE_ENDIAN); + if (event_flags & EVENT_FLAG_STACKINFO) { + /* stack specific data */ + } + proto_tree_add_item(bblog_tree, hf_payload_len, tvb, 264, 4, ENC_LITTLE_ENDIAN); + return tvb_captured_length(tvb); +} + +void +proto_register_bblog(void) +{ + static hf_register_info hf[] = { + { &hf_ticks, { "Ticks", "bblog.ticks", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_serial_nr, { "Serial Number", "bblog.serial_nr", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_stack_id, { "Stack Identifier", "bblog.stack_id", FT_UINT8, BASE_DEC, NULL , 0x0, NULL, HFILL} }, + { &hf_event_id, { "Event Identifier", "bblog.event_id", FT_UINT8, BASE_DEC, VALS(event_identifier_values), 0x0, NULL, HFILL} }, + { &hf_event_flags, { "Event Flags", "bblog.event_flags", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL} }, + { &hf_event_flags_rxbuf, { "Bit", "bblog.event_flags_rxbuf", FT_BOOLEAN, 8, TFS(&event_flags_rxbuf), EVENT_FLAG_RXBUF, NULL, HFILL} }, + { &hf_event_flags_txbuf, { "Bit", "bblog.event_flags_txbuf", FT_BOOLEAN, 8, TFS(&event_flags_txbuf), EVENT_FLAG_TXBUF, NULL, HFILL} }, + { &hf_event_flags_hdr, { "Bit", "bblog.event_flags_hdr", FT_BOOLEAN, 8, TFS(&event_flags_hdr), EVENT_FLAG_HDR, NULL, HFILL} }, + { &hf_event_flags_verbose, { "Bit", "bblog.event_flags_verbose", FT_BOOLEAN, 8, TFS(&event_flags_verbose), EVENT_FLAG_VERBOSE, NULL, HFILL} }, + { &hf_event_flags_stack, { "Bit", "bblog.event_flags_stack", FT_BOOLEAN, 8, TFS(&event_flags_stack), EVENT_FLAG_STACKINFO, NULL, HFILL} }, + { &hf_errno, { "Error Number", "bblog.errno", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_rxb_acc, { "Receive Buffer ACC", "bblog.rxb_acc", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_rxb_ccc, { "Receive Buffer CCC", "bblog.rxb_ccc", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_rxb_spare, { "Receive Buffer Spare", "bblog.rxb_spare", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_txb_acc, { "Send Buffer ACC", "bblog.txb_acc", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_txb_ccc, { "Send Buffer CCC", "bblog.txb_accs", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_txb_spare, { "Send Buffer Spare", "bblog.txb_spare", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_state, { "TCP State", "bblog.state", FT_UINT32, BASE_DEC, VALS(tcp_state_values), 0x0, NULL, HFILL} }, + { &hf_starttime, { "Starttime", "bblog.starttime", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_iss, { "Initial Sending Sequence Number (ISS)", "bblog.iss", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_flags, { "TCB Flags", "bblog.flags", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL} }, + { &hf_snd_una, { "Oldest Unacknowledged Sequence Number (SND.UNA)", "bblog.snd_una", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_snd_max, { "Newest Sequence Number Sent (SND.MAX)", "bblog.snd_max", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_snd_cwnd, { "Congestion Window", "bblog.snd_cwnd", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_snd_nxt, { "Next Sequence Number (SND.NXT)", "bblog.snd_nxt", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_snd_recover, { "Recovery Sequence Number (SND.RECOVER)", "bblog.snd_recover", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_snd_wnd, { "Send Window (SND.WND)", "bblog.snd_wnd", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_snd_ssthresh, { "Slowstart Threshold (SSTHREASH)", "bblog.snd_ssthresh", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_srtt, { "Smoothed Round Trip Time (SRTT)", "bblog.srtt", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_rttvar, { "Round Trip Timer Variance (RTTVAR)", "bblog.rttvar", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_rcv_up, { "Receive Urgent Pointer (RCV.UP)", "bblog.rcv_up", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_rcv_adv, { "Receive Advanced (RCV.ADV)", "bblog.rcv_adv", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_flags2, { "TCB Flags2", "bblog.flags2", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL} }, + { &hf_rcv_nxt, { "Receive Next (RCV.NXT)", "bblog.rcv_nxt", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_rcv_wnd, { "Receive Window (RCV.WND)", "bblog.rcv_wnd", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_dupacks, { "Duplicate Acknowledgements", "bblog.dupacks", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_seg_qlen, { "Segment Queue Length", "bblog.seg_qlen", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_snd_num_holes, { "Number of Holes", "bblog.snd_num_holes", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_flex_1, { "Flex 1", "bblog.flex_1", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_flex_2, { "Flex 2", "bblog.flex_2", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_first_byte_in, { "Time of First Byte In", "bblog.first_byte_in", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_first_byte_out, { "Time of First Byte Out", "bblog.first_byte_out", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_snd_scale, { "Shift Count for Send Window", "bblog.snd_shift", FT_UINT8, BASE_DEC, NULL, SND_SCALE_MASK, NULL, HFILL} }, + { &hf_rcv_scale, { "Shift Count for Receive Window", "bblog.rcv_shift", FT_UINT8, BASE_DEC, NULL, RCV_SCALE_MASK, NULL, HFILL} }, + { &hf_pad_1, { "Padding", "bblog.pad_1", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_pad_2, { "Padding", "bblog.pad_2", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_pad_3, { "Padding", "bblog.pad_3", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + { &hf_payload_len, { "TCP Payload Length", "bblog.payload_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} }, + }; + + /* Setup protocol subtree array */ + static gint *ett[] = { + &ett_bblog, + &ett_bblog_flags + }; + + /* Register the protocol name and description */ + proto_bblog = proto_register_protocol("Black Box Log", "BBLog", "bblog"); + + /* Required function calls to register the header fields and subtrees */ + proto_register_field_array(proto_bblog, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + register_dissector("bblog", dissect_bblog, proto_bblog); +} + +void +proto_reg_handoff_bblog(void) +{ +} + +/* + * 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: + */ diff --git a/epan/dissectors/packet-frame.c b/epan/dissectors/packet-frame.c index 41b178ccd3..24cef3a4c5 100644 --- a/epan/dissectors/packet-frame.c +++ b/epan/dissectors/packet-frame.c @@ -47,6 +47,7 @@ void proto_reg_handoff_frame(void); static int proto_frame = -1; static int proto_pkt_comment = -1; static int proto_syscall = -1; +static int proto_bblog = -1; static int hf_frame_arrival_time = -1; static int hf_frame_shift_offset = -1; @@ -94,6 +95,9 @@ static int hf_frame_pack_symbol_error = -1; static int hf_frame_wtap_encap = -1; static int hf_frame_cb_pen = -1; static int hf_frame_cb_copy_allowed = -1; +static int hf_frame_bblog = -1; +static int hf_frame_bblog_ticks = -1; +static int hf_frame_bblog_serial_nr = -1; static int hf_comments_text = -1; static gint ett_frame = -1; @@ -101,6 +105,7 @@ static gint ett_ifname = -1; static gint ett_flags = -1; static gint ett_comments = -1; static gint ett_verdict = -1; +static gint ett_bblog = -1; static expert_field ei_comments_text = EI_INIT; static expert_field ei_arrive_time_out_of_range = EI_INIT; @@ -111,6 +116,7 @@ static int frame_tap = -1; static dissector_handle_t docsis_handle; static dissector_handle_t sysdig_handle; static dissector_handle_t systemd_journal_handle; +static dissector_handle_t bblog_handle; /* Preferences */ static gboolean show_file_off = FALSE; @@ -350,6 +356,7 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* const color_filter_t *color_filter; dissector_handle_t dissector_handle; fr_foreach_t fr_user_data; + struct nflx_tcpinfo tcpinfo; tree=parent_tree; @@ -451,7 +458,14 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* break; case REC_TYPE_CUSTOM_BLOCK: - pinfo->current_proto = "PCAPNG Custom Block"; + switch (pinfo->rec->rec_header.custom_block_header.pen) { + case PEN_NFLX: + pinfo->current_proto = "Black Box Log"; + break; + default: + pinfo->current_proto = "PCAPNG Custom Block"; + break; + } break; default: @@ -581,18 +595,28 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* break; case REC_TYPE_CUSTOM_BLOCK: - ti = proto_tree_add_protocol_format(tree, proto_frame, tvb, 0, tvb_captured_length(tvb), - "PCAPNG Custom Block %u: %u byte%s", - pinfo->num, frame_len, frame_plurality); - if (generate_bits_field) { - proto_item_append_text(ti, " (%u bits)", frame_len * 8); + switch (pinfo->rec->rec_header.custom_block_header.pen) { + case PEN_NFLX: + ti = proto_tree_add_protocol_format(tree, proto_bblog, tvb, 0, tvb_captured_length(tvb), + "Black Box Log %u: %u byte%s", + pinfo->num, frame_len, frame_plurality); + break; + default: + ti = proto_tree_add_protocol_format(tree, proto_frame, tvb, 0, tvb_captured_length(tvb), + "PCAPNG Custom Block %u: %u byte%s", + pinfo->num, frame_len, frame_plurality); + if (generate_bits_field) { + proto_item_append_text(ti, " (%u bits)", frame_len * 8); + } + proto_item_append_text(ti, " of custom data and options, PEN %s (%u)", + enterprises_lookup(pinfo->rec->rec_header.custom_block_header.pen, "Unknown"), + pinfo->rec->rec_header.custom_block_header.pen); + proto_item_append_text(ti, ", copying%s allowed", + pinfo->rec->rec_header.custom_block_header.copy_allowed ? "" : " not"); + break; } - proto_item_append_text(ti, " of custom data and options, PEN %s (%u)", - enterprises_lookup(pinfo->rec->rec_header.custom_block_header.pen, "Unknown"), - pinfo->rec->rec_header.custom_block_header.pen); - proto_item_append_text(ti, ", copying%s allowed", - pinfo->rec->rec_header.custom_block_header.copy_allowed ? "" : " not"); break; + } fh_tree = proto_item_add_subtree(ti, ett_frame); @@ -763,6 +787,15 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* proto_tree_add_uint(fh_tree, hf_link_number, tvb, 0, 0, pinfo->link_number); } + if (WTAP_OPTTYPE_SUCCESS == wtap_block_get_nflx_custom_option(fr_data->pkt_block, NFLX_OPT_TYPE_TCPINFO, (char *)&tcpinfo, sizeof(struct nflx_tcpinfo))) { + proto_tree *bblog_tree; + proto_item *bblog_item; + + bblog_item = proto_tree_add_string(fh_tree, hf_frame_bblog, tvb, 0, 0, ""); + bblog_tree = proto_item_add_subtree(bblog_item, ett_bblog); + proto_tree_add_uint(bblog_tree, hf_frame_bblog_ticks, tvb, 0, 0, tcpinfo.tlb_ticks); + proto_tree_add_uint(bblog_tree, hf_frame_bblog_serial_nr, tvb, 0, 0, tcpinfo.tlb_sn); + } } if (show_file_off) { @@ -874,19 +907,29 @@ dissect_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* break; case REC_TYPE_CUSTOM_BLOCK: - col_set_str(pinfo->cinfo, COL_PROTOCOL, "PCAPNG"); - proto_tree_add_uint_format_value(fh_tree, hf_frame_cb_pen, tvb, 0, 0, - pinfo->rec->rec_header.custom_block_header.pen, - "%s (%u)", - enterprises_lookup(pinfo->rec->rec_header.custom_block_header.pen, "Unknown"), - pinfo->rec->rec_header.custom_block_header.pen); - proto_tree_add_boolean(fh_tree, hf_frame_cb_copy_allowed, tvb, 0, 0, pinfo->rec->rec_header.custom_block_header.copy_allowed); - col_add_fstr(pinfo->cinfo, COL_INFO, "Custom Block: PEN = %s (%d), will%s be copied", - enterprises_lookup(pinfo->rec->rec_header.custom_block_header.pen, "Unknown"), - pinfo->rec->rec_header.custom_block_header.pen, - pinfo->rec->rec_header.custom_block_header.copy_allowed ? "" : " not"); - call_data_dissector(tvb, pinfo, parent_tree); + switch (pinfo->rec->rec_header.custom_block_header.pen) { + case PEN_NFLX: + call_dissector_with_data(bblog_handle, + tvb, pinfo, parent_tree, + (void *)pinfo->pseudo_header); + break; + default: + col_set_str(pinfo->cinfo, COL_PROTOCOL, "PCAPNG"); + proto_tree_add_uint_format_value(fh_tree, hf_frame_cb_pen, tvb, 0, 0, + pinfo->rec->rec_header.custom_block_header.pen, + "%s (%u)", + enterprises_lookup(pinfo->rec->rec_header.custom_block_header.pen, "Unknown"), + pinfo->rec->rec_header.custom_block_header.pen); + proto_tree_add_boolean(fh_tree, hf_frame_cb_copy_allowed, tvb, 0, 0, pinfo->rec->rec_header.custom_block_header.copy_allowed); + col_add_fstr(pinfo->cinfo, COL_INFO, "Custom Block: PEN = %s (%d), will%s be copied", + enterprises_lookup(pinfo->rec->rec_header.custom_block_header.pen, "Unknown"), + pinfo->rec->rec_header.custom_block_header.pen, + pinfo->rec->rec_header.custom_block_header.copy_allowed ? "" : " not"); + call_data_dissector(tvb, pinfo, parent_tree); + break; + } break; + } #ifdef _MSC_VER } __except(EXCEPTION_EXECUTE_HANDLER /* handle all exceptions */) { @@ -1283,6 +1326,22 @@ proto_register_frame(void) { "Copying", "frame.cb_copy", FT_BOOLEAN, BASE_DEC, TFS(&tfs_allowed_not_allowed), 0x0, "Whether the custom block will be written or not", HFILL }}, + + { &hf_frame_bblog, + { "Black Box Log", "frame.bblog", + FT_STRING, BASE_NONE, NULL, 0x0, + NULL, HFILL }}, + + { &hf_frame_bblog_ticks, + { "Ticks", "frame.bblog.ticks", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL}}, + + { &hf_frame_bblog_serial_nr, + { "Serial Number", "frame.bblog.serial_nr", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL}}, + }; static hf_register_info hf_encap = @@ -1297,6 +1356,7 @@ proto_register_frame(void) &ett_flags, &ett_comments, &ett_verdict, + &ett_bblog }; static ei_register_info ei[] = { @@ -1326,6 +1386,7 @@ proto_register_frame(void) proto_frame = proto_register_protocol("Frame", "Frame", "frame"); proto_pkt_comment = proto_register_protocol_in_name_only("Packet comments", "Pkt_Comment", "pkt_comment", proto_frame, FT_PROTOCOL); proto_syscall = proto_register_protocol("System Call", "Syscall", "syscall"); + proto_bblog = proto_get_id_by_filter_name("bblog"); proto_register_field_array(proto_frame, hf, array_length(hf)); proto_register_field_array(proto_frame, &hf_encap, 1); @@ -1378,6 +1439,7 @@ proto_reg_handoff_frame(void) docsis_handle = find_dissector_add_dependency("docsis", proto_frame); sysdig_handle = find_dissector_add_dependency("sysdig", proto_frame); systemd_journal_handle = find_dissector_add_dependency("systemd_journal", proto_frame); + bblog_handle = find_dissector_add_dependency("bblog", proto_frame); } /* diff --git a/epan/frame_data.c b/epan/frame_data.c index c60271e674..9365110f8a 100644 --- a/epan/frame_data.c +++ b/epan/frame_data.c @@ -207,9 +207,18 @@ frame_data_init(frame_data *fdata, guint32 num, const wtap_rec *rec, /* * XXX - is cum_bytes supposed to count non-packet bytes? */ - fdata->pkt_len = rec->rec_header.custom_block_header.length; - fdata->cum_bytes = cum_bytes + rec->rec_header.custom_block_header.length; - fdata->cap_len = rec->rec_header.custom_block_header.length; + switch (rec->rec_header.custom_block_header.pen) { + case PEN_NFLX: + fdata->pkt_len = rec->rec_header.custom_block_header.length - 4; + fdata->cum_bytes = cum_bytes + rec->rec_header.custom_block_header.length - 4; + fdata->cap_len = rec->rec_header.custom_block_header.length - 4; + break; + default: + fdata->pkt_len = rec->rec_header.custom_block_header.length; + fdata->cum_bytes = cum_bytes + rec->rec_header.custom_block_header.length; + fdata->cap_len = rec->rec_header.custom_block_header.length; + break; + } break; } diff --git a/epan/packet.c b/epan/packet.c index 417774a32a..f53193a19b 100644 --- a/epan/packet.c +++ b/epan/packet.c @@ -508,7 +508,14 @@ dissect_record(epan_dissect_t *edt, int file_type_subtype, break; case REC_TYPE_CUSTOM_BLOCK: - record_type = "PCAPNG Custom Block"; + switch (rec->rec_header.custom_block_header.pen) { + case PEN_NFLX: + record_type = "Black Box Log Block"; + break; + default: + record_type = "PCAPNG Custom Block"; + break; + } break; default: @@ -560,8 +567,16 @@ dissect_record(epan_dissect_t *edt, int file_type_subtype, break; case REC_TYPE_CUSTOM_BLOCK: - edt->pi.pseudo_header = NULL; + switch (rec->rec_header.custom_block_header.pen) { + case PEN_NFLX: + edt->pi.pseudo_header = NULL; + break; + default: + edt->pi.pseudo_header = NULL; + break; + } break; + } edt->pi.fd = fd; diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c index 811576fdb9..e443b47764 100644 --- a/wiretap/pcapng.c +++ b/wiretap/pcapng.c @@ -233,11 +233,14 @@ typedef struct wtapng_simple_packet_s { /* Section data in private struct */ typedef struct section_info_t { - gboolean byte_swapped; /**< TRUE if this section is not in our byte order */ - guint16 version_major; /**< Major version number of this section */ - guint16 version_minor; /**< Minor version number of this section */ - GArray *interfaces; /**< Interfaces found in this section */ - gint64 shb_off; /**< File offset of the SHB for this section */ + gboolean byte_swapped; /**< TRUE if this section is not in our byte order */ + guint16 version_major; /**< Major version number of this section */ + guint16 version_minor; /**< Minor version number of this section */ + GArray *interfaces; /**< Interfaces found in this section */ + gint64 shb_off; /**< File offset of the SHB for this section */ + guint32 bblog_version; /**< BBLog: version used */ + guint64 bblog_offset_tv_sec; /**< BBLog: UTC offset */ + guint64 bblog_offset_tv_usec; } section_info_t; /* Interface data in private struct */ @@ -612,14 +615,98 @@ pcapng_process_bytes_option(wtapng_block_t *wblock, guint16 option_code, wtap_block_add_bytes_option(wblock->block, option_code, (const char *)option_content, option_length); } +static gboolean +pcapng_process_nflx_custom_option(wtapng_block_t *wblock, + section_info_t *section_info, + const guint8 *value, guint16 length) +{ + struct nflx_dumpinfo dumpinfo; + guint32 type, version; + gint64 dumptime, temp; + + if (length < 4) { + ws_debug("Length = %u too small", length); + return FALSE; + } + memcpy(&type, value, sizeof(guint32)); + type = GUINT32_FROM_LE(type); + value += 4; + length -= 4; + ws_debug("Handling type = %u, payload of length = %u", type, length); + switch (type) { + case NFLX_OPT_TYPE_VERSION: + if (length == sizeof(guint32)) { + memcpy(&version, value, sizeof(guint32)); + version = GUINT32_FROM_LE(version); + ws_debug("BBLog version: %u", version); + section_info->bblog_version = version; + } else { + ws_debug("BBLog version parameter has strange length: %u", length); + } + break; + case NFLX_OPT_TYPE_TCPINFO: + ws_debug("BBLog tcpinfo of length: %u", length); + if (wblock->type == BLOCK_TYPE_CB_COPY) { + ws_buffer_assure_space(wblock->frame_buffer, length); + wblock->rec->rec_header.custom_block_header.length = length + 4; + memcpy(ws_buffer_start_ptr(wblock->frame_buffer), value, length); + memcpy(&temp, value, sizeof(guint64)); + temp = GUINT64_FROM_LE(temp); + wblock->rec->ts.secs = section_info->bblog_offset_tv_sec + temp; + memcpy(&temp, value + sizeof(guint64), sizeof(guint64)); + temp = GUINT64_FROM_LE(temp); + wblock->rec->ts.nsecs = (guint32)(section_info->bblog_offset_tv_usec + temp) * 1000; + if (wblock->rec->ts.nsecs >= 1000000000) { + wblock->rec->ts.secs += 1; + wblock->rec->ts.nsecs -= 1000000000; + } + wblock->rec->presence_flags = WTAP_HAS_TS; + wblock->internal = FALSE; + } + break; + case NFLX_OPT_TYPE_DUMPINFO: + if (length == sizeof(struct nflx_dumpinfo)) { + memcpy(&dumpinfo, value, sizeof(struct nflx_dumpinfo)); + section_info->bblog_offset_tv_sec = GUINT64_FROM_LE(dumpinfo.tlh_offset_tv_sec); + section_info->bblog_offset_tv_usec = GUINT64_FROM_LE(dumpinfo.tlh_offset_tv_usec); + ws_debug("BBLog dumpinfo time offset: %" G_GUINT64_FORMAT, section_info->bblog_offset_tv_sec); + } else { + ws_debug("BBLog dumpinfo parameter has strange length: %u", length); + } + break; + case NFLX_OPT_TYPE_DUMPTIME: + if (length == sizeof(gint64)) { + memcpy(&dumptime, value, sizeof(gint64)); + dumptime = GINT64_FROM_LE(dumptime); + ws_debug("BBLog dumpinfo time offset: %" G_GUINT64_FORMAT, dumptime); + } else { + ws_debug("BBLog dumptime parameter has strange length: %u", length); + } + break; + case NFLX_OPT_TYPE_STACKNAME: + if (length >= 2) { + ws_debug("BBLog stack name: %.*s(%u)", length - 1, value + 1, *(guint8 *)value); + } else { + ws_debug("BBLog stack name has strange length: %u)", length); + } + break; + default: + ws_debug("Unknown type: %u, length: %u", type, length); + break; + } + return wtap_block_add_nflx_custom_option(wblock->block, type, value, length) == WTAP_OPTTYPE_SUCCESS; +} + static gboolean pcapng_process_custom_option(wtapng_block_t *wblock, - const section_info_t *section_info, + section_info_t *section_info, guint16 option_code, guint16 option_length, const guint8 *option_content, + gboolean little_endian, int *err, gchar **err_info) { guint32 pen; + gboolean ret; if (option_length < 4) { *err = WTAP_ERR_BAD_FILE; @@ -628,18 +715,22 @@ pcapng_process_custom_option(wtapng_block_t *wblock, return FALSE; } memcpy(&pen, option_content, sizeof(guint32)); - if (section_info->byte_swapped) { + if (little_endian) { + pen = GUINT32_FROM_LE(pen); + } else if (section_info->byte_swapped) { pen = GUINT32_SWAP_LE_BE(pen); } switch (pen) { + case PEN_NFLX: + ret = pcapng_process_nflx_custom_option(wblock, section_info, option_content + 4, option_length - 4); + break; default: + ret = wtap_block_add_custom_option(wblock->block, option_code, pen, option_content + 4, option_length - 4) == WTAP_OPTTYPE_SUCCESS; ws_debug("Custom option type 0x%04x with unknown pen %u with custom data of length %u", option_code, pen, option_length - 4); - if (wtap_block_add_custom_option(wblock->block, option_code, pen, option_content + 4, option_length - 4) != WTAP_OPTTYPE_SUCCESS) { - return FALSE; - } break; } - return TRUE; + ws_debug("returning %d", ret); + return ret; } #ifdef HAVE_PLUGINS @@ -682,13 +773,14 @@ pcapng_process_unhandled_option(wtapng_block_t *wblock _U_, static gboolean pcapng_process_options(FILE_T fh, wtapng_block_t *wblock, - const section_info_t *section_info, + section_info_t *section_info, guint opt_cont_buf_len, gboolean (*process_option)(wtapng_block_t *, const section_info_t *, guint16, guint16, const guint8 *, int *, gchar **), + gboolean little_endian, int *err, gchar **err_info) { guint8 *option_content; /* Allocate as large as the options block */ @@ -738,7 +830,10 @@ pcapng_process_options(FILE_T fh, wtapng_block_t *wblock, } option_code = oh->option_code; option_length = oh->option_length; - if (section_info->byte_swapped) { + if (little_endian) { + option_code = GUINT16_FROM_LE(option_code); + option_length = GUINT16_FROM_LE(option_length); + } else if (section_info->byte_swapped) { option_code = GUINT16_SWAP_LE_BE(option_code); option_length = GUINT16_SWAP_LE_BE(option_length); } @@ -776,6 +871,7 @@ pcapng_process_options(FILE_T fh, wtapng_block_t *wblock, if (!pcapng_process_custom_option(wblock, section_info, option_code, option_length, option_ptr, + little_endian, err, err_info)) { g_free(option_content); return FALSE; @@ -783,7 +879,8 @@ pcapng_process_options(FILE_T fh, wtapng_block_t *wblock, break; default: - if (!(*process_option)(wblock, section_info, option_code, + if (process_option == NULL || + !(*process_option)(wblock, (const section_info_t *)section_info, option_code, option_length, option_ptr, err, err_info)) { g_free(option_content); @@ -995,7 +1092,7 @@ pcapng_read_section_header_block(FILE_T fh, pcapng_block_header_t *bh, opt_cont_buf_len = bh->block_total_length - MIN_SHB_SIZE; if (!pcapng_process_options(fh, wblock, section_info, opt_cont_buf_len, pcapng_process_section_header_block_option, - err, err_info)) + FALSE, err, err_info)) return PCAPNG_BLOCK_ERROR; /* @@ -1190,7 +1287,7 @@ pcapng_process_if_descr_block_option(wtapng_block_t *wblock, /* "Interface Description Block" */ static gboolean pcapng_read_if_descr_block(wtap *wth, FILE_T fh, pcapng_block_header_t *bh, - const section_info_t *section_info, + section_info_t *section_info, wtapng_block_t *wblock, int *err, gchar **err_info) { guint64 time_units_per_second = 1000000; /* default = 10^6 */ @@ -1258,7 +1355,7 @@ pcapng_read_if_descr_block(wtap *wth, FILE_T fh, pcapng_block_header_t *bh, opt_cont_buf_len = bh->block_total_length - MIN_IDB_SIZE; if (!pcapng_process_options(fh, wblock, section_info, opt_cont_buf_len, pcapng_process_if_descr_block_option, - err, err_info)) + FALSE, err, err_info)) return FALSE; /* @@ -1557,7 +1654,7 @@ pcapng_process_packet_block_option(wtapng_block_t *wblock, static gboolean pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, - const section_info_t *section_info, + section_info_t *section_info, wtapng_block_t *wblock, int *err, gchar **err_info, gboolean enhanced) { @@ -1763,7 +1860,7 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, (int)sizeof(bh->block_total_length); if (!pcapng_process_options(fh, wblock, section_info, opt_cont_buf_len, pcapng_process_packet_block_option, - err, err_info)) + FALSE, err, err_info)) return FALSE; /* @@ -2033,7 +2130,7 @@ pcapng_process_name_resolution_block_option(wtapng_block_t *wblock, static gboolean pcapng_read_name_resolution_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, - const section_info_t *section_info, + section_info_t *section_info, wtapng_block_t *wblock, int *err, gchar **err_info) { @@ -2254,7 +2351,7 @@ read_options: opt_cont_buf_len = to_read; if (!pcapng_process_options(fh, wblock, section_info, opt_cont_buf_len, pcapng_process_name_resolution_block_option, - err, err_info)) + FALSE, err, err_info)) return FALSE; ws_buffer_free(&nrb_rec); @@ -2334,7 +2431,7 @@ pcapng_process_interface_statistics_block_option(wtapng_block_t *wblock, static gboolean pcapng_read_interface_statistics_block(FILE_T fh, pcapng_block_header_t *bh, - const section_info_t *section_info, + section_info_t *section_info, wtapng_block_t *wblock, int *err, gchar **err_info) { @@ -2386,7 +2483,7 @@ pcapng_read_interface_statistics_block(FILE_T fh, pcapng_block_header_t *bh, (MIN_BLOCK_SIZE + (guint)sizeof isb); /* fixed and variable part, including padding */ if (!pcapng_process_options(fh, wblock, section_info, opt_cont_buf_len, pcapng_process_interface_statistics_block_option, - err, err_info)) + FALSE, err, err_info)) return FALSE; /* @@ -2397,6 +2494,71 @@ pcapng_read_interface_statistics_block(FILE_T fh, pcapng_block_header_t *bh, return TRUE; } +#define NFLX_BLOCK_TYPE_EVENT 1 +#define NFLX_BLOCK_TYPE_SKIP 2 + +typedef struct pcapng_nflx_custom_block_s { + guint32 nflx_type; +} pcapng_nflx_custom_block_t; + +#define MIN_NFLX_CB_SIZE ((guint32)(MIN_CB_SIZE + sizeof(pcapng_nflx_custom_block_t))) + +static gboolean +pcapng_read_nflx_custom_block(FILE_T fh, pcapng_block_header_t *bh, + section_info_t *section_info, + wtapng_block_t *wblock, + int *err, gchar **err_info) +{ + pcapng_nflx_custom_block_t nflx_cb; + guint opt_cont_buf_len; + guint32 type, skipped; + + if (bh->block_total_length < MIN_NFLX_CB_SIZE) { + *err = WTAP_ERR_BAD_FILE; + *err_info = g_strdup_printf("pcapng_read_nflx_custom_block: total block length %u is too small (< %u)", + bh->block_total_length, MIN_NFLX_CB_SIZE); + return FALSE; + } + + opt_cont_buf_len = bh->block_total_length - MIN_NFLX_CB_SIZE; + wblock->rec->rec_type = REC_TYPE_CUSTOM_BLOCK; + wblock->rec->rec_header.custom_block_header.pen = PEN_NFLX; + /* "NFLX Custom Block" read fixed part */ + if (!wtap_read_bytes(fh, &nflx_cb, sizeof nflx_cb, err, err_info)) { + ws_debug("Failed to read nflx type"); + return FALSE; + } + type = GUINT32_FROM_LE(nflx_cb.nflx_type); + ws_debug("BBLog type: %u", type); + switch (type) { + case NFLX_BLOCK_TYPE_EVENT: + wblock->rec->rec_header.custom_block_header.custom_data_header.nflx_custom_data_header.type = BBLOG_TYPE_EVENT_BLOCK; + opt_cont_buf_len = bh->block_total_length - MIN_NFLX_CB_SIZE; + ws_debug("event"); + break; + case NFLX_BLOCK_TYPE_SKIP: + wblock->rec->rec_header.custom_block_header.custom_data_header.nflx_custom_data_header.type = BBLOG_TYPE_SKIPPED_BLOCK; + if (!wtap_read_bytes(fh, &skipped, sizeof(guint32), err, err_info)) { + ws_debug("Failed to read skipped"); + return FALSE; + } + wblock->rec->rec_header.custom_block_header.custom_data_header.nflx_custom_data_header.skipped = GUINT32_FROM_LE(skipped); + ws_debug("skipped: %u", wblock->rec->rec_header.custom_block_header.custom_data_header.nflx_custom_data_header.skipped); + opt_cont_buf_len = bh->block_total_length - MIN_NFLX_CB_SIZE - sizeof(guint32); + break; + default: + ws_debug("Unknown type %u", type); + return FALSE; + } + + /* Options */ + if (!pcapng_process_options(fh, wblock, section_info, opt_cont_buf_len, + NULL, TRUE, err, err_info)) + return FALSE; + + return TRUE; +} + static gboolean pcapng_handle_generic_custom_block(FILE_T fh, pcapng_block_header_t *bh, guint32 pen, wtapng_block_t *wblock, @@ -2425,9 +2587,10 @@ pcapng_handle_generic_custom_block(FILE_T fh, pcapng_block_header_t *bh, wblock->internal = FALSE; return TRUE; } + static gboolean pcapng_read_custom_block(FILE_T fh, pcapng_block_header_t *bh, - const section_info_t *section_info, + section_info_t *section_info, wtapng_block_t *wblock, int *err, gchar **err_info) { @@ -2445,6 +2608,8 @@ pcapng_read_custom_block(FILE_T fh, pcapng_block_header_t *bh, return FALSE; } + wblock->block = wtap_block_create(WTAP_BLOCK_CUSTOM); + /* Custom block read fixed part */ if (!wtap_read_bytes(fh, &cb, sizeof cb, err, err_info)) { ws_debug("failed to read pen"); @@ -2458,6 +2623,10 @@ pcapng_read_custom_block(FILE_T fh, pcapng_block_header_t *bh, ws_debug("pen %u, custom data and option length %u", pen, bh->block_total_length - MIN_CB_SIZE); switch (pen) { + case PEN_NFLX: + if (!pcapng_read_nflx_custom_block(fh, bh, section_info, wblock, err, err_info)) + return FALSE; + break; default: if (!pcapng_handle_generic_custom_block(fh, bh, pen, wblock, err, err_info)) { return FALSE; @@ -2465,6 +2634,9 @@ pcapng_read_custom_block(FILE_T fh, pcapng_block_header_t *bh, break; } + wblock->rec->block = wblock->block; + wblock->block = NULL; + return TRUE; } @@ -3521,7 +3693,18 @@ static guint32 pcapng_compute_custom_option_size(wtap_optval_t *optval) { size_t size, pad; - size = optval->custom_opt.custom_data_len + sizeof(guint32); + /* PEN */ + size = sizeof(guint32); + switch (optval->custom_opt.pen) { + case PEN_NFLX: + /* PEN */ + size += sizeof(guint32); + size += optval->custom_opt.data.nflx_data.custom_data_len; + break; + default: + size += optval->custom_opt.data.generic_data.custom_data_len; + break; + } if (size > 65535) { size = 65535; } @@ -3957,13 +4140,28 @@ static gboolean pcapng_write_if_filter_option(wtap_dumper *wdh, guint option_id, static gboolean pcapng_write_custom_option(wtap_dumper *wdh, guint option_id, wtap_optval_t *optval, int *err) { struct pcapng_option_header option_hdr; + gsize pad; + gsize size; const guint32 zero_pad = 0; - size_t pad; + guint32 pen, type; + gboolean use_little_endian; if ((option_id == OPT_CUSTOM_STR_NO_COPY) || (option_id == OPT_CUSTOM_BIN_NO_COPY)) return TRUE; - if (optval->custom_opt.custom_data_len + sizeof(guint32) > 65535) { + ws_debug("PEN %d", optval->custom_opt.pen); + switch (optval->custom_opt.pen) { + case PEN_NFLX: + size = sizeof(guint32) + sizeof(guint32) + optval->custom_opt.data.nflx_data.custom_data_len; + use_little_endian = optval->custom_opt.data.nflx_data.use_little_endian; + break; + default: + size = sizeof(guint32) + optval->custom_opt.data.generic_data.custom_data_len; + use_little_endian = false; + break; + } + ws_debug("use_little_endian %d", use_little_endian); + if (size > 65535) { /* * Too big to fit in the option. * Don't write anything. @@ -3975,30 +4173,57 @@ static gboolean pcapng_write_custom_option(wtap_dumper *wdh, guint option_id, wt /* write option header */ option_hdr.type = (guint16)option_id; - option_hdr.value_length = (guint16)(optval->custom_opt.custom_data_len + sizeof(guint32)); + option_hdr.value_length = (guint16)size; + if (use_little_endian) { + option_hdr.type = GUINT16_TO_LE(option_hdr.type); + option_hdr.value_length = GUINT16_TO_LE(option_hdr.value_length); + } if (!wtap_dump_file_write(wdh, &option_hdr, sizeof(struct pcapng_option_header), err)) return FALSE; wdh->bytes_dumped += sizeof(struct pcapng_option_header); /* write PEN */ - if (!wtap_dump_file_write(wdh, &optval->custom_opt.pen, sizeof(guint32), err)) + pen = optval->custom_opt.pen; + if (use_little_endian) { + pen = GUINT32_TO_LE(pen); + } + if (!wtap_dump_file_write(wdh, &pen, sizeof(guint32), err)) return FALSE; wdh->bytes_dumped += sizeof(guint32); - /* write custom data */ - if (!wtap_dump_file_write(wdh, optval->custom_opt.custom_data, optval->custom_opt.custom_data_len, err)) - return FALSE; - wdh->bytes_dumped += optval->custom_opt.custom_data_len; + switch (optval->custom_opt.pen) { + case PEN_NFLX: + /* write NFLX type */ + type = GUINT32_TO_LE(optval->custom_opt.data.nflx_data.type); + ws_debug("type=%d", type); + if (!wtap_dump_file_write(wdh, &type, sizeof(guint32), err)) + return FALSE; + wdh->bytes_dumped += sizeof(guint32); + /* write custom data */ + if (!wtap_dump_file_write(wdh, optval->custom_opt.data.nflx_data.custom_data, optval->custom_opt.data.nflx_data.custom_data_len, err)) { + return FALSE; + } + wdh->bytes_dumped += optval->custom_opt.data.nflx_data.custom_data_len; + break; + default: + /* write custom data */ + if (!wtap_dump_file_write(wdh, optval->custom_opt.data.generic_data.custom_data, optval->custom_opt.data.generic_data.custom_data_len, err)) { + return FALSE; + } + wdh->bytes_dumped += optval->custom_opt.data.generic_data.custom_data_len; + break; + } /* write padding (if any) */ - if ((optval->custom_opt.custom_data_len % 4)) { - pad = 4 - (optval->custom_opt.custom_data_len % 4); + if (size % 4 != 0) { + pad = 4 - (size % 4); } else { pad = 0; } if (pad != 0) { - if (!wtap_dump_file_write(wdh, &zero_pad, pad, err)) + if (!wtap_dump_file_write(wdh, &zero_pad, pad, err)) { return FALSE; + } wdh->bytes_dumped += pad; } ws_debug("Wrote custom option: type %u, length %u", option_hdr.type, option_hdr.value_length); @@ -4591,9 +4816,9 @@ pcapng_write_custom_block(wtap_dumper *wdh, const wtap_rec *rec, /* write block header */ bh.block_type = BLOCK_TYPE_CB_COPY; bh.block_total_length = (guint32)sizeof(bh) + (guint32)sizeof(cb) + rec->rec_header.custom_block_header.length + pad_len + 4; - ws_debug("writing %u bytes, %u padded", + ws_debug("writing %u bytes, %u padded, PEN %u", rec->rec_header.custom_block_header.length, - bh.block_total_length); + bh.block_total_length, rec->rec_header.custom_block_header.pen); if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err)) { return FALSE; } @@ -4605,6 +4830,7 @@ pcapng_write_custom_block(wtap_dumper *wdh, const wtap_rec *rec, return FALSE; } wdh->bytes_dumped += sizeof cb; + ws_debug("wrote PEN = %u", cb.pen); /* write custom data */ if (!wtap_dump_file_write(wdh, pd, rec->rec_header.custom_block_header.length, err)) { @@ -4625,6 +4851,76 @@ pcapng_write_custom_block(wtap_dumper *wdh, const wtap_rec *rec, sizeof bh.block_total_length, err)) { return FALSE; } + wdh->bytes_dumped += sizeof bh.block_total_length; + + return TRUE; +} + +static gboolean +pcapng_write_bblog_block(wtap_dumper *wdh, const wtap_rec *rec, + const guint8 *pd _U_, int *err) +{ + pcapng_block_header_t bh; + pcapng_write_block_t block_data; + gsize options_len; + guint32 pen, skipped, type; + + options_len = wtap_block_get_options_size_padded(rec->block) + 4; + + /* write block header */ + bh.block_type = BLOCK_TYPE_CB_COPY; + bh.block_total_length = (guint32)(sizeof(bh) + sizeof(guint32) + sizeof(guint32) + options_len + 4); + if (rec->rec_header.custom_block_header.custom_data_header.nflx_custom_data_header.type == BBLOG_TYPE_SKIPPED_BLOCK) { + bh.block_total_length += (guint32)sizeof(guint32); + } + ws_debug("writing %u bytes, type %u", + bh.block_total_length, rec->rec_header.custom_block_header.custom_data_header.nflx_custom_data_header.type); + if (!wtap_dump_file_write(wdh, &bh, sizeof(bh), err)) { + return FALSE; + } + wdh->bytes_dumped += sizeof bh; + + /* write PEN */ + pen = PEN_NFLX; + if (!wtap_dump_file_write(wdh, &pen, sizeof(guint32), err)) { + return FALSE; + } + wdh->bytes_dumped += sizeof(guint32); + ws_debug("wrote PEN = %u", pen); + + /* write type */ + type = GUINT32_TO_LE(rec->rec_header.custom_block_header.custom_data_header.nflx_custom_data_header.type); + if (!wtap_dump_file_write(wdh, &type, sizeof(guint32), err)) { + return FALSE; + } + wdh->bytes_dumped += sizeof(guint32); + ws_debug("wrote type = %u", rec->rec_header.custom_block_header.custom_data_header.nflx_custom_data_header.type); + + if (rec->rec_header.custom_block_header.custom_data_header.nflx_custom_data_header.type == BBLOG_TYPE_SKIPPED_BLOCK) { + skipped = GUINT32_TO_LE(rec->rec_header.custom_block_header.custom_data_header.nflx_custom_data_header.skipped); + if (!wtap_dump_file_write(wdh, &skipped, sizeof(guint32), err)) { + return FALSE; + } + wdh->bytes_dumped += sizeof(guint32); + ws_debug("wrote skipped = %u", rec->rec_header.custom_block_header.custom_data_header.nflx_custom_data_header.skipped); + } + + block_data.wdh = wdh; + block_data.err = err; + if (!wtap_block_foreach_option(rec->block, pcapng_write_option_cb, &block_data)) { + return FALSE; + } + /* Write end of options if we have options */ + if (!pcapng_write_option_eofopt(wdh, err)) { + return FALSE; + } + + /* write block footer */ + if (!wtap_dump_file_write(wdh, &bh.block_total_length, + sizeof bh.block_total_length, err)) { + return FALSE; + } + wdh->bytes_dumped += sizeof bh.block_total_length; return TRUE; } @@ -4752,7 +5048,7 @@ put_nrb_option(wtap_block_t block _U_, guint option_id, wtap_opttype_e option_ty case OPT_CUSTOM_STR_COPY: case OPT_CUSTOM_BIN_COPY: /* Custom options don't consider pad bytes part of the length */ - size = (guint32)(optval->custom_opt.custom_data_len + sizeof(guint32)) & 0xffff; + size = (guint32)(optval->custom_opt.data.generic_data.custom_data_len + sizeof(guint32)) & 0xffff; option_hdr.type = (guint16)option_id; option_hdr.value_length = (guint16)size; memcpy(*opt_ptrp, &option_hdr, 4); @@ -4761,8 +5057,8 @@ put_nrb_option(wtap_block_t block _U_, guint option_id, wtap_opttype_e option_ty memcpy(*opt_ptrp, &optval->custom_opt.pen, sizeof(guint32)); *opt_ptrp += sizeof(guint32); - memcpy(*opt_ptrp, optval->custom_opt.custom_data, size); - *opt_ptrp += size; + memcpy(*opt_ptrp, optval->custom_opt.data.generic_data.custom_data, optval->custom_opt.data.generic_data.custom_data_len); + *opt_ptrp += optval->custom_opt.data.generic_data.custom_data_len; if ((size % 4)) { pad = 4 - (size % 4); @@ -5398,8 +5694,17 @@ static gboolean pcapng_dump(wtap_dumper *wdh, break; case REC_TYPE_CUSTOM_BLOCK: - if (!pcapng_write_custom_block(wdh, rec, pd, err)) { - return FALSE; + switch (rec->rec_header.custom_block_header.pen) { + case PEN_NFLX: + if (!pcapng_write_bblog_block(wdh, rec, pd, err)) { + return FALSE; + } + break; + default: + if (!pcapng_write_custom_block(wdh, rec, pd, err)) { + return FALSE; + } + break; } break; diff --git a/wiretap/wtap.h b/wiretap/wtap.h index d10e6856c1..a332e66f13 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -1323,8 +1323,17 @@ typedef struct { guint32 length; /* length of the record */ guint32 pen; /* private enterprise number */ gboolean copy_allowed; /* CB can be written */ + union { + struct nflx { + guint32 type; /* block type */ + guint32 skipped; /* Used if type == BBLOG_TYPE_SKIPPED_BLOCK */ + } nflx_custom_data_header; + } custom_data_header; } wtap_custom_block_header; +#define BBLOG_TYPE_EVENT_BLOCK 1 +#define BBLOG_TYPE_SKIPPED_BLOCK 2 + typedef struct { guint rec_type; /* what type of record is this? */ guint32 presence_flags; /* what stuff do we have? */ diff --git a/wiretap/wtap_opttypes.c b/wiretap/wtap_opttypes.c index dfbab29f32..928b64b2d5 100644 --- a/wiretap/wtap_opttypes.c +++ b/wiretap/wtap_opttypes.c @@ -299,7 +299,14 @@ static void wtap_block_free_option(wtap_block_t block, wtap_option_t *opt) break; case WTAP_OPTTYPE_CUSTOM: - g_free(opt->value.custom_opt.custom_data); + switch (opt->value.custom_opt.pen) { + case PEN_NFLX: + g_free(opt->value.custom_opt.data.nflx_data.custom_data); + break; + default: + g_free(opt->value.custom_opt.data.generic_data.custom_data); + break; + } break; default: @@ -433,7 +440,14 @@ wtap_block_copy(wtap_block_t dest_block, wtap_block_t src_block) break; case WTAP_OPTTYPE_CUSTOM: - wtap_block_add_custom_option(dest_block, src_opt->option_id, src_opt->value.custom_opt.pen, src_opt->value.custom_opt.custom_data, src_opt->value.custom_opt.custom_data_len); + switch (src_opt->value.custom_opt.pen) { + case PEN_NFLX: + wtap_block_add_nflx_custom_option(dest_block, src_opt->value.custom_opt.data.nflx_data.type, src_opt->value.custom_opt.data.nflx_data.custom_data, src_opt->value.custom_opt.data.nflx_data.custom_data_len); + break; + default: + wtap_block_add_custom_option(dest_block, src_opt->option_id, src_opt->value.custom_opt.pen, src_opt->value.custom_opt.data.generic_data.custom_data, src_opt->value.custom_opt.data.generic_data.custom_data_len); + break; + } break; } } @@ -500,7 +514,18 @@ wtap_block_option_get_value_size(wtap_opttype_e option_type, wtap_optval_t *opti break; case WTAP_OPTTYPE_CUSTOM: - ret_val += sizeof(guint32) + option->custom_opt.custom_data_len; + /* PEN */ + ret_val += sizeof(guint32); + switch (option->custom_opt.pen) { + case PEN_NFLX: + /* NFLX type */ + ret_val += sizeof(guint32); + ret_val += option->custom_opt.data.nflx_data.custom_data_len; + break; + default: + ret_val += option->custom_opt.data.generic_data.custom_data_len; + break; + } break; } return ret_val; @@ -1204,6 +1229,190 @@ wtap_block_get_if_filter_option_value(wtap_block_t block, guint option_id, if_fi return WTAP_OPTTYPE_SUCCESS; } +wtap_opttype_return_val +wtap_block_add_nflx_custom_option(wtap_block_t block, guint32 type, const char *custom_data, gsize custom_data_len) +{ + wtap_opttype_return_val ret; + wtap_option_t *opt; + + ret = wtap_block_add_option_common(block, OPT_CUSTOM_BIN_COPY, WTAP_OPTTYPE_CUSTOM, &opt); + if (ret != WTAP_OPTTYPE_SUCCESS) + return ret; + opt->value.custom_opt.pen = PEN_NFLX; + opt->value.custom_opt.data.nflx_data.type = type; + opt->value.custom_opt.data.nflx_data.custom_data_len = custom_data_len; + opt->value.custom_opt.data.nflx_data.custom_data = g_memdup2(custom_data, custom_data_len); + opt->value.custom_opt.data.nflx_data.use_little_endian = (block->info->block_type == WTAP_BLOCK_CUSTOM); + return WTAP_OPTTYPE_SUCCESS; +} + +wtap_opttype_return_val +wtap_block_get_nflx_custom_option(wtap_block_t block, guint32 nflx_type, char *nflx_custom_data _U_, gsize nflx_custom_data_len) +{ + const wtap_opttype_t *opttype; + wtap_option_t *opt; + guint i; + + if (block == NULL) { + return WTAP_OPTTYPE_BAD_BLOCK; + } + opttype = GET_OPTION_TYPE(block->info->options, OPT_CUSTOM_BIN_COPY); + if (opttype == NULL) { + return WTAP_OPTTYPE_NO_SUCH_OPTION; + } + if (opttype->data_type != WTAP_OPTTYPE_CUSTOM) { + return WTAP_OPTTYPE_TYPE_MISMATCH; + } + + for (i = 0; i < block->options->len; i++) { + opt = &g_array_index(block->options, wtap_option_t, i); + if ((opt->option_id == OPT_CUSTOM_BIN_COPY) && + (opt->value.custom_opt.pen == PEN_NFLX) && + (opt->value.custom_opt.data.nflx_data.type == nflx_type)) { + break; + } + } + if (i == block->options->len) { + return WTAP_OPTTYPE_NOT_FOUND; + } + if (nflx_custom_data_len < opt->value.custom_opt.data.nflx_data.custom_data_len) { + return WTAP_OPTTYPE_TYPE_MISMATCH; + } + switch (nflx_type) { + case NFLX_OPT_TYPE_VERSION: { + guint32 *src, *dst; + + ws_assert(nflx_custom_data_len == sizeof(guint32)); + src = (guint32 *)opt->value.custom_opt.data.nflx_data.custom_data; + dst = (guint32 *)nflx_custom_data; + *dst = GUINT32_FROM_LE(*src); + break; + } + case NFLX_OPT_TYPE_TCPINFO: { + struct nflx_tcpinfo *src, *dst; + + ws_assert(nflx_custom_data_len == sizeof(struct nflx_tcpinfo)); + src = (struct nflx_tcpinfo *)opt->value.custom_opt.data.nflx_data.custom_data; + dst = (struct nflx_tcpinfo *)nflx_custom_data; + dst->tlb_tv_sec = GUINT64_FROM_LE(src->tlb_tv_sec); + dst->tlb_tv_usec = GUINT64_FROM_LE(src->tlb_tv_usec); + dst->tlb_ticks = GUINT32_FROM_LE(src->tlb_ticks); + dst->tlb_sn = GUINT32_FROM_LE(src->tlb_sn); + dst->tlb_stackid = src->tlb_stackid; + dst->tlb_eventid = src->tlb_eventid; + dst->tlb_eventflags = GUINT16_FROM_LE(src->tlb_eventflags); + dst->tlb_errno = GINT32_FROM_LE(src->tlb_errno); + dst->tlb_rxbuf_tls_sb_acc = GUINT32_FROM_LE(src->tlb_rxbuf_tls_sb_acc); + dst->tlb_rxbuf_tls_sb_ccc = GUINT32_FROM_LE(src->tlb_rxbuf_tls_sb_ccc); + dst->tlb_rxbuf_tls_sb_spare = GUINT32_FROM_LE(src->tlb_rxbuf_tls_sb_spare); + dst->tlb_txbuf_tls_sb_acc = GUINT32_FROM_LE(src->tlb_txbuf_tls_sb_acc); + dst->tlb_txbuf_tls_sb_ccc = GUINT32_FROM_LE(src->tlb_txbuf_tls_sb_ccc); + dst->tlb_txbuf_tls_sb_spare = GUINT32_FROM_LE(src->tlb_txbuf_tls_sb_spare); + dst->tlb_state = GINT32_FROM_LE(src->tlb_state); + dst->tlb_starttime = GUINT32_FROM_LE(src->tlb_starttime); + dst->tlb_iss = GUINT32_FROM_LE(src->tlb_iss); + dst->tlb_flags = GUINT32_FROM_LE(src->tlb_flags); + dst->tlb_snd_una = GUINT32_FROM_LE(src->tlb_snd_una); + dst->tlb_snd_max = GUINT32_FROM_LE(src->tlb_snd_max); + dst->tlb_snd_cwnd = GUINT32_FROM_LE(src->tlb_snd_cwnd); + dst->tlb_snd_nxt = GUINT32_FROM_LE(src->tlb_snd_nxt); + dst->tlb_snd_recover = GUINT32_FROM_LE(src->tlb_snd_recover); + dst->tlb_snd_wnd = GUINT32_FROM_LE(src->tlb_snd_wnd); + dst->tlb_snd_ssthresh = GUINT32_FROM_LE(src->tlb_snd_ssthresh); + dst->tlb_srtt = GUINT32_FROM_LE(src->tlb_srtt); + dst->tlb_rttvar = GUINT32_FROM_LE(src->tlb_rttvar); + dst->tlb_rcv_up = GUINT32_FROM_LE(src->tlb_rcv_up); + dst->tlb_rcv_adv = GUINT32_FROM_LE(src->tlb_rcv_adv); + dst->tlb_flags2 = GUINT32_FROM_LE(src->tlb_flags2); + dst->tlb_rcv_nxt = GUINT32_FROM_LE(src->tlb_rcv_nxt); + dst->tlb_rcv_wnd = GUINT32_FROM_LE(src->tlb_rcv_wnd); + dst->tlb_dupacks = GUINT32_FROM_LE(src->tlb_dupacks); + dst->tlb_segqlen = GINT32_FROM_LE(src->tlb_segqlen); + dst->tlb_snd_numholes = GINT32_FROM_LE(src->tlb_snd_numholes); + dst->tlb_flex1 = GUINT32_FROM_LE(src->tlb_flex1); + dst->tlb_flex2 = GUINT32_FROM_LE(src->tlb_flex2); + dst->tlb_fbyte_in = GUINT32_FROM_LE(src->tlb_fbyte_in); + dst->tlb_fbyte_out = GUINT32_FROM_LE(src->tlb_fbyte_out); + dst->tlb_snd_scale = src->tlb_snd_scale; + dst->tlb_rcv_scale = src->tlb_rcv_scale; + for (i = 0; i < 3; i++) { + dst->_pad[i] = src->_pad[i]; + } + dst->tlb_stackinfo_bbr_cur_del_rate = GUINT64_FROM_LE(src->tlb_stackinfo_bbr_cur_del_rate); + dst->tlb_stackinfo_bbr_delRate = GUINT64_FROM_LE(src->tlb_stackinfo_bbr_delRate); + dst->tlb_stackinfo_bbr_rttProp = GUINT64_FROM_LE(src->tlb_stackinfo_bbr_rttProp); + dst->tlb_stackinfo_bbr_bw_inuse = GUINT64_FROM_LE(src->tlb_stackinfo_bbr_bw_inuse); + dst->tlb_stackinfo_bbr_inflight = GUINT32_FROM_LE(src->tlb_stackinfo_bbr_inflight); + dst->tlb_stackinfo_bbr_applimited = GUINT32_FROM_LE(src->tlb_stackinfo_bbr_applimited); + dst->tlb_stackinfo_bbr_delivered = GUINT32_FROM_LE(src->tlb_stackinfo_bbr_delivered); + dst->tlb_stackinfo_bbr_timeStamp = GUINT32_FROM_LE(src->tlb_stackinfo_bbr_timeStamp); + dst->tlb_stackinfo_bbr_epoch = GUINT32_FROM_LE(src->tlb_stackinfo_bbr_epoch); + dst->tlb_stackinfo_bbr_lt_epoch = GUINT32_FROM_LE(src->tlb_stackinfo_bbr_lt_epoch); + dst->tlb_stackinfo_bbr_pkts_out = GUINT32_FROM_LE(src->tlb_stackinfo_bbr_pkts_out); + dst->tlb_stackinfo_bbr_flex1 = GUINT32_FROM_LE(src->tlb_stackinfo_bbr_flex1); + dst->tlb_stackinfo_bbr_flex2 = GUINT32_FROM_LE(src->tlb_stackinfo_bbr_flex2); + dst->tlb_stackinfo_bbr_flex3 = GUINT32_FROM_LE(src->tlb_stackinfo_bbr_flex3); + dst->tlb_stackinfo_bbr_flex4 = GUINT32_FROM_LE(src->tlb_stackinfo_bbr_flex4); + dst->tlb_stackinfo_bbr_flex5 = GUINT32_FROM_LE(src->tlb_stackinfo_bbr_flex5); + dst->tlb_stackinfo_bbr_flex6 = GUINT32_FROM_LE(src->tlb_stackinfo_bbr_flex6); + dst->tlb_stackinfo_bbr_lost = GUINT32_FROM_LE(src->tlb_stackinfo_bbr_lost); + dst->tlb_stackinfo_bbr_pacing_gain = GUINT16_FROM_LE(src->tlb_stackinfo_bbr_lost); + dst->tlb_stackinfo_bbr_cwnd_gain = GUINT16_FROM_LE(src->tlb_stackinfo_bbr_lost); + dst->tlb_stackinfo_bbr_flex7 = GUINT16_FROM_LE(src->tlb_stackinfo_bbr_flex7); + dst->tlb_stackinfo_bbr_bbr_state = src->tlb_stackinfo_bbr_bbr_state; + dst->tlb_stackinfo_bbr_bbr_substate = src->tlb_stackinfo_bbr_bbr_substate; + dst->tlb_stackinfo_bbr_inhpts = src->tlb_stackinfo_bbr_inhpts; + dst->tlb_stackinfo_bbr_ininput = src->tlb_stackinfo_bbr_ininput; + dst->tlb_stackinfo_bbr_use_lt_bw = src->tlb_stackinfo_bbr_use_lt_bw; + dst->tlb_stackinfo_bbr_flex8 = src->tlb_stackinfo_bbr_flex8; + dst->tlb_stackinfo_bbr_pkt_epoch = GUINT32_FROM_LE(src->tlb_stackinfo_bbr_pkt_epoch); + dst->tlb_len = GUINT32_FROM_LE(src->tlb_len); + break; + } + case NFLX_OPT_TYPE_DUMPINFO: { + struct nflx_dumpinfo *src, *dst; + + ws_assert(nflx_custom_data_len == sizeof(struct nflx_dumpinfo)); + src = (struct nflx_dumpinfo *)opt->value.custom_opt.data.nflx_data.custom_data; + dst = (struct nflx_dumpinfo *)nflx_custom_data; + dst->tlh_version = GUINT32_FROM_LE(src->tlh_version); + dst->tlh_type = GUINT32_FROM_LE(src->tlh_type); + dst->tlh_length = GUINT64_FROM_LE(src->tlh_length); + dst->tlh_ie_fport = src->tlh_ie_fport; + dst->tlh_ie_lport = src->tlh_ie_lport; + for (i = 0; i < 4; i++) { + dst->tlh_ie_faddr_addr32[i] = src->tlh_ie_faddr_addr32[i]; + dst->tlh_ie_laddr_addr32[i] = src->tlh_ie_laddr_addr32[i]; + } + dst->tlh_ie_zoneid = src->tlh_ie_zoneid; + dst->tlh_offset_tv_sec = GUINT64_FROM_LE(src->tlh_offset_tv_sec); + dst->tlh_offset_tv_usec = GUINT64_FROM_LE(src->tlh_offset_tv_usec); + memcpy(dst->tlh_id, src->tlh_id, 64); + memcpy(dst->tlh_reason, src->tlh_reason, 32); + memcpy(dst->tlh_tag, src->tlh_tag, 32); + dst->tlh_af = src->tlh_af; + memcpy(dst->_pad, src->_pad, 7); + break; + } + case NFLX_OPT_TYPE_DUMPTIME: { + guint64 *src, *dst; + + ws_assert(nflx_custom_data_len == sizeof(guint64)); + src = (guint64 *)opt->value.custom_opt.data.nflx_data.custom_data; + dst = (guint64 *)nflx_custom_data; + *dst = GUINT64_FROM_LE(*src); + break; + } + case NFLX_OPT_TYPE_STACKNAME: + ws_assert(nflx_custom_data_len >= 2); + memcpy(nflx_custom_data, opt->value.custom_opt.data.nflx_data.custom_data, nflx_custom_data_len); + break; + default: + return WTAP_OPTTYPE_NOT_FOUND; + } + return WTAP_OPTTYPE_SUCCESS; +} + wtap_opttype_return_val wtap_block_add_custom_option(wtap_block_t block, guint option_id, guint32 pen, const char *custom_data, gsize custom_data_len) { @@ -1214,8 +1423,8 @@ wtap_block_add_custom_option(wtap_block_t block, guint option_id, guint32 pen, c if (ret != WTAP_OPTTYPE_SUCCESS) return ret; opt->value.custom_opt.pen = pen; - opt->value.custom_opt.custom_data_len = custom_data_len; - opt->value.custom_opt.custom_data = g_memdup2(custom_data, custom_data_len); + opt->value.custom_opt.data.generic_data.custom_data_len = custom_data_len; + opt->value.custom_opt.data.generic_data.custom_data = g_memdup2(custom_data, custom_data_len); return WTAP_OPTTYPE_SUCCESS; } @@ -1414,6 +1623,12 @@ static void pkt_create(wtap_block_t block) block->mandatory_data = NULL; } +static void cb_create(wtap_block_t block) +{ + /* Ensure this is null, so when g_free is called on it, it simply returns */ + block->mandatory_data = NULL; +} + void wtap_opttypes_initialize(void) { static wtap_blocktype_t shb_block = { @@ -1639,6 +1854,16 @@ void wtap_opttypes_initialize(void) WTAP_OPTTYPE_FLAG_MULTIPLE_ALLOWED }; + static wtap_blocktype_t cb_block = { + WTAP_BLOCK_CUSTOM, /* block_type */ + "CB", /* name */ + "Packet Block", /* description */ + cb_create, /* create */ + NULL, /* free_mand */ + NULL, /* copy_mand */ + NULL /* options */ + }; + /* * Register the SHB and the options that can appear in it. */ @@ -1699,6 +1924,11 @@ void wtap_opttypes_initialize(void) wtap_opttype_option_register(&pkt_block, OPT_PKT_HASH, &pkt_hash); wtap_opttype_option_register(&pkt_block, OPT_PKT_VERDICT, &pkt_verdict); + /* + * Register the CB and the options that can appear in it. + */ + wtap_opttype_block_register(&cb_block); + #ifdef DEBUG_COUNT_REFS memset(blocks_active, 0, sizeof(blocks_active)); #endif diff --git a/wiretap/wtap_opttypes.h b/wiretap/wtap_opttypes.h index e9c11fd9df..e0fadac663 100644 --- a/wiretap/wtap_opttypes.h +++ b/wiretap/wtap_opttypes.h @@ -323,16 +323,40 @@ typedef struct if_filter_opt_s { } data; } if_filter_opt_t; +/* https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers */ +#define PEN_NFLX 10949 + /* * Structure describing a custom option. */ typedef struct custom_opt_s { guint32 pen; - gsize custom_data_len; - gchar *custom_data; + union { + struct generic_custom_opt_data { + gsize custom_data_len; + gchar *custom_data; + } generic_data; + struct nflx_custom_opt_data { + guint32 type; + gsize custom_data_len; + gchar *custom_data; + gboolean use_little_endian; + } nflx_data; + } data; } custom_opt_t; +/* + * Structure describing a NFLX custom option. + */ + +typedef struct nflx_custom_opt_s { + gboolean nflx_use_little_endian; + guint32 nflx_type; + gsize nflx_custom_data_len; + gchar *nflx_custom_data; +} nflx_custom_opt_t; + /* * Structure describing a value of an option. */ @@ -356,6 +380,114 @@ typedef struct { wtap_optval_t value; /**< value */ } wtap_option_t; +#define NFLX_OPT_TYPE_VERSION 1 +#define NFLX_OPT_TYPE_TCPINFO 2 +#define NFLX_OPT_TYPE_DUMPINFO 4 +#define NFLX_OPT_TYPE_DUMPTIME 5 +#define NFLX_OPT_TYPE_STACKNAME 6 + +struct nflx_dumpinfo { + guint32 tlh_version; + guint32 tlh_type; + guint64 tlh_length; + guint16 tlh_ie_fport; + guint16 tlh_ie_lport; + guint32 tlh_ie_faddr_addr32[4]; + guint32 tlh_ie_laddr_addr32[4]; + guint32 tlh_ie_zoneid; + guint64 tlh_offset_tv_sec; + guint64 tlh_offset_tv_usec; + char tlh_id[64]; + char tlh_reason[32]; + char tlh_tag[32]; + guint8 tlh_af; + guint8 _pad[7]; +}; + +/* Flags used in tlb_eventflags */ +#define NFLX_TLB_FLAG_RXBUF 0x0001 /* Includes receive buffer info */ +#define NFLX_TLB_FLAG_TXBUF 0x0002 /* Includes send buffer info */ +#define NFLX_TLB_FLAG_HDR 0x0004 /* Includes a TCP header */ +#define NFLX_TLB_FLAG_VERBOSE 0x0008 /* Includes function/line numbers */ +#define NFLX_TLB_FLAG_STACKINFO 0x0010 /* Includes stack-specific info */ + +struct nflx_tcpinfo { + guint64 tlb_tv_sec; + guint64 tlb_tv_usec; + guint32 tlb_ticks; + guint32 tlb_sn; + guint8 tlb_stackid; + guint8 tlb_eventid; + guint16 tlb_eventflags; + gint32 tlb_errno; + guint32 tlb_rxbuf_tls_sb_acc; + guint32 tlb_rxbuf_tls_sb_ccc; + guint32 tlb_rxbuf_tls_sb_spare; + guint32 tlb_txbuf_tls_sb_acc; + guint32 tlb_txbuf_tls_sb_ccc; + guint32 tlb_txbuf_tls_sb_spare; + gint32 tlb_state; + guint32 tlb_starttime; + guint32 tlb_iss; + guint32 tlb_flags; + guint32 tlb_snd_una; + guint32 tlb_snd_max; + guint32 tlb_snd_cwnd; + guint32 tlb_snd_nxt; + guint32 tlb_snd_recover; + guint32 tlb_snd_wnd; + guint32 tlb_snd_ssthresh; + guint32 tlb_srtt; + guint32 tlb_rttvar; + guint32 tlb_rcv_up; + guint32 tlb_rcv_adv; + guint32 tlb_flags2; + guint32 tlb_rcv_nxt; + guint32 tlb_rcv_wnd; + guint32 tlb_dupacks; + gint32 tlb_segqlen; + gint32 tlb_snd_numholes; + guint32 tlb_flex1; + guint32 tlb_flex2; + guint32 tlb_fbyte_in; + guint32 tlb_fbyte_out; + guint8 tlb_snd_scale:4, + tlb_rcv_scale:4; + guint8 _pad[3]; + + /* The following fields might become part of a union */ + guint64 tlb_stackinfo_bbr_cur_del_rate; + guint64 tlb_stackinfo_bbr_delRate; + guint64 tlb_stackinfo_bbr_rttProp; + guint64 tlb_stackinfo_bbr_bw_inuse; + guint32 tlb_stackinfo_bbr_inflight; + guint32 tlb_stackinfo_bbr_applimited; + guint32 tlb_stackinfo_bbr_delivered; + guint32 tlb_stackinfo_bbr_timeStamp; + guint32 tlb_stackinfo_bbr_epoch; + guint32 tlb_stackinfo_bbr_lt_epoch; + guint32 tlb_stackinfo_bbr_pkts_out; + guint32 tlb_stackinfo_bbr_flex1; + guint32 tlb_stackinfo_bbr_flex2; + guint32 tlb_stackinfo_bbr_flex3; + guint32 tlb_stackinfo_bbr_flex4; + guint32 tlb_stackinfo_bbr_flex5; + guint32 tlb_stackinfo_bbr_flex6; + guint32 tlb_stackinfo_bbr_lost; + guint16 tlb_stackinfo_bbr_pacing_gain; + guint16 tlb_stackinfo_bbr_cwnd_gain; + guint16 tlb_stackinfo_bbr_flex7; + guint8 tlb_stackinfo_bbr_bbr_state; + guint8 tlb_stackinfo_bbr_bbr_substate; + guint8 tlb_stackinfo_bbr_inhpts; + guint8 tlb_stackinfo_bbr_ininput; + guint8 tlb_stackinfo_bbr_use_lt_bw; + guint8 tlb_stackinfo_bbr_flex8; + guint32 tlb_stackinfo_bbr_pkt_epoch; + + guint32 tlb_len; +}; + struct wtap_dumper; typedef void (*wtap_block_create_func)(wtap_block_t block); @@ -808,6 +940,30 @@ wtap_block_set_if_filter_option_value(wtap_block_t block, guint option_id, if_fi WS_DLL_PUBLIC wtap_opttype_return_val wtap_block_get_if_filter_option_value(wtap_block_t block, guint option_id, if_filter_opt_t* value) G_GNUC_WARN_UNUSED_RESULT; +/** Add an NFLX custom option to a block + * + * @param[in] block Block to which to add the option + * @param[in] nflx_type NFLX option type + * @param[in] nflx_custom_data pointer to the data + * @param[in] nflx_custom_data_len length of custom_data + * @return wtap_opttype_return_val - WTAP_OPTTYPE_SUCCESS if successful, + * error code otherwise + */ +WS_DLL_PUBLIC wtap_opttype_return_val +wtap_block_add_nflx_custom_option(wtap_block_t block, guint32 nflx_type, const char *nflx_custom_data, gsize nflx_custom_data_len); + +/** Get an if_filter option value from a block + * + * @param[in] block Block from which to get the option value + * @param[in] nflx_type type of the option + * @param[out] nflx_custom_data Returned value of NFLX custom option value + * @param[in] nflx_custom_data_len size of buffer provided in nflx_custom_data + * @return wtap_opttype_return_val - WTAP_OPTTYPE_SUCCESS if successful, + * error code otherwise + */ +WS_DLL_PUBLIC wtap_opttype_return_val +wtap_block_get_nflx_custom_option(wtap_block_t block, guint32 nflx_type, char *nflx_custom_data, gsize nflx_custom_data_len); + /** Add an custom option to a block * * @param[in] block Block to which to add the option