diff options
Diffstat (limited to 'epan/dissectors/packet-srt.c')
-rw-r--r-- | epan/dissectors/packet-srt.c | 647 |
1 files changed, 523 insertions, 124 deletions
diff --git a/epan/dissectors/packet-srt.c b/epan/dissectors/packet-srt.c index 5028e8c3cd..28452fb517 100644 --- a/epan/dissectors/packet-srt.c +++ b/epan/dissectors/packet-srt.c @@ -15,91 +15,119 @@ * with secure streams and easy firewall traversal, bringing the best * quality live video over the worst networks. * - * http://www.srtalliance.org + * Internet draft: + * https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01 * - * As no version of the standard could be found on the above site, a - * network protocol description can be found in a sample implementation:: - * - * https://github.com/Haivision/srt/blob/master/docs/handshake.md + * Open-source implementation: + * https://github.com/Haivision/srt */ #include <config.h> -#include <wsutil/str_util.h> #include <epan/packet.h> #include <epan/expert.h> #include <epan/conversation.h> +#include <wsutil/str_util.h> +#include <wsutil/inet_addr.h> /* Prototypes */ void proto_reg_handoff_srt(void); void proto_register_srt(void); /* Initialize the protocol */ -static int proto_srt = -1; -static int hf_srt_iscontrol = -1; -static int hf_srt_type = -1; -static int hf_srt_exttype = -1; -static int hf_srt_exttype_none = -1; -static int hf_srt_seqno = -1; -static int hf_srt_ack_seqno = -1; -static int hf_srt_ackno = -1; -static int hf_srt_msgno = -1; -static int hf_srt_msgno_pb = -1; -static int hf_srt_msgno_inorder = -1; -static int hf_srt_msgno_enctypes = -1; -static int hf_srt_msgno_rexmit = -1; -static int hf_srt_timestamp = -1; -static int hf_srt_id = -1; -static int hf_srt_addinfo = -1; -static int hf_srt_rtt = -1; -static int hf_srt_rttvar = -1; -static int hf_srt_bufavail = -1; -static int hf_srt_rate = -1; -static int hf_srt_bandwidth = -1; -static int hf_srt_rcvrate = -1; +static int proto_srt; +static int hf_srt_iscontrol; +static int hf_srt_type; +static int hf_srt_exttype; +static int hf_srt_exttype_none; +static int hf_srt_seqno; +static int hf_srt_ack_seqno; +static int hf_srt_ackno; +static int hf_srt_msgno; +static int hf_srt_msgno_pb; +static int hf_srt_msgno_inorder; +static int hf_srt_msgno_enctypes; +static int hf_srt_msgno_rexmit; +static int hf_srt_timestamp; +static int hf_srt_id; +static int hf_srt_addinfo; +static int hf_srt_rtt; +static int hf_srt_rttvar; +static int hf_srt_bufavail; +static int hf_srt_rate; +static int hf_srt_bandwidth; +static int hf_srt_rcvrate; /* SRT Handshake */ -static int hf_srt_handshake_version = -1; -static int hf_srt_handshake_type_v4 = -1; -static int hf_srt_handshake_enc_field_v5 = -1; -static int hf_srt_handshake_ext_field_v5 = -1; -static int hf_srt_handshake_ext_field_v5_flag_hsreq = -1; -static int hf_srt_handshake_ext_field_v5_flag_kmreq = -1; -static int hf_srt_handshake_ext_field_v5_flag_config = -1; -static int hf_srt_handshake_isn = -1; -static int hf_srt_handshake_mtu = -1; -static int hf_srt_handshake_flow_window = -1; -static int hf_srt_handshake_reqtype = -1; -static int hf_srt_handshake_id = -1; -static int hf_srt_handshake_cookie = -1; -static int hf_srt_handshake_peerip = -1; +static int hf_srt_handshake_version; +static int hf_srt_handshake_type_v4; +static int hf_srt_handshake_enc_field_v5; +static int hf_srt_handshake_ext_field_v5; +static int hf_srt_handshake_ext_field_v5_flag_hsreq; +static int hf_srt_handshake_ext_field_v5_flag_kmreq; +static int hf_srt_handshake_ext_field_v5_flag_config; +static int hf_srt_handshake_isn; +static int hf_srt_handshake_mtu; +static int hf_srt_handshake_flow_window; +static int hf_srt_handshake_reqtype; +static int hf_srt_handshake_failure_type; +static int hf_srt_handshake_id; +static int hf_srt_handshake_cookie; +static int hf_srt_handshake_peerip; /* SRT Handshake Extension */ -static int hf_srt_handshake_ext_version = -1; -static int hf_srt_handshake_ext_flags = -1; -static int hf_srt_handshake_ext_flag_tsbpd_snd = -1; -static int hf_srt_handshake_ext_flag_tsbpd_rcv = -1; -static int hf_srt_handshake_ext_flag_haicrypt = -1; -static int hf_srt_handshake_ext_flag_tlpkt_drop = -1; -static int hf_srt_handshake_ext_flag_nak_report = -1; -static int hf_srt_handshake_ext_flag_rexmit = -1; -static int hf_srt_handshake_ext_flag_stream = -1; - -static int hf_srt_srths_blocktype = -1; -static int hf_srt_srths_blocklen = -1; -static int hf_srt_srths_agent_latency = -1; // TSBPD delay -static int hf_srt_srths_peer_latency = -1; // TSBPD delay -static int hf_srt_srtkm_msg = -1; -static int hf_srt_srtkm_error = -1; -static int hf_srt_srths_sid = -1; -static int hf_srt_srths_conjestcontrol = -1; - -static gint ett_srt = -1; -static gint ett_srt_handshake_ext_flags = -1; -static gint ett_srt_handshake_ext_field_flags = -1; - -static expert_field ei_srt_nak_seqno = EI_INIT; -static expert_field ei_srt_hs_ext_hsreq_len = EI_INIT; -static expert_field ei_srt_hs_ext_type = EI_INIT; +static int hf_srt_handshake_ext_version; +static int hf_srt_handshake_ext_flags; +static int hf_srt_handshake_ext_flag_tsbpd_snd; +static int hf_srt_handshake_ext_flag_tsbpd_rcv; +static int hf_srt_handshake_ext_flag_haicrypt; +static int hf_srt_handshake_ext_flag_tlpkt_drop; +static int hf_srt_handshake_ext_flag_nak_report; +static int hf_srt_handshake_ext_flag_rexmit; +static int hf_srt_handshake_ext_flag_stream; + +/* Key Material (KM) */ +static int hf_srt_km; +static int hf_srt_km_s; +static int hf_srt_km_v; +static int hf_srt_km_pt; +static int hf_srt_km_sign; +static int hf_srt_km_resv1; +static int hf_srt_km_kk; +static int hf_srt_km_keki; +static int hf_srt_km_cipher; +static int hf_srt_km_auth; +static int hf_srt_km_se; +static int hf_srt_km_resv2; +static int hf_srt_km_resv3; +static int hf_srt_km_slen; +static int hf_srt_km_klen; +static int hf_srt_km_salt; +static int hf_srt_km_wrap; + +/* HS Extension: Group */ +static int hf_srt_hs_ext_group_id; +static int hf_srt_hs_ext_group_type; +static int hf_srt_hs_ext_group_flags; +static int hf_srt_hs_ext_group_weight; + +static int hf_srt_srths_blocktype; +static int hf_srt_srths_blocklen; +static int hf_srt_srths_agent_latency; // TSBPD delay +static int hf_srt_srths_peer_latency; // TSBPD delay +static int hf_srt_srtkm_msg; +static int hf_srt_srtkm_error; +static int hf_srt_srths_sid; +static int hf_srt_srths_congestcontrol; +static int hf_srt_hs_ext_filter; + +static gint ett_srt; +static gint ett_srt_handshake_ext_flags; +static gint ett_srt_handshake_ext_field_flags; + +static expert_field ei_srt_nak_seqno; +static expert_field ei_srt_hs_ext_hsreq_len; +static expert_field ei_srt_hs_ext_type; +static expert_field ei_srt_hs_ext_group_len; static dissector_handle_t srt_udp_handle; @@ -109,6 +137,12 @@ static dissector_handle_t srt_udp_handle; #define SRT_TYPE_CONTROL 1 #define SRT_CONTROL_MASK (~0x80000000) +#define SRT_KM_S_MASK 0x80 +#define SRT_KM_V_MASK 0x70 +#define SRT_KM_PT_MASK 0x0F +#define SRT_KM_KK_MASK 0x03 +#define SRT_KM_RESV1_MASK 0xFC + #define SRT_LOSS_SEQUENCE_FIRST 0x80000000 #define SRT_LOSS_SEQUENCE_MASK (~SRT_LOSS_SEQUENCE_FIRST) @@ -167,9 +201,10 @@ enum PacketBoundary /* Rest of the bits are for message sequence number */ #define SRT_MSGNO_MSGNO_MASK 0x03ffffff +#define SRT_MSGNO_REXMIT_FLG 0x04000000 -/* The message types used by UDT protocol. This is a part of UDT +/* The message types used by SRT protocol. This is a part of SRT * protocol and should never be changed. */ enum UDTMessageType @@ -194,7 +229,9 @@ enum UDTMessageType #define SRT_CMD_KMREQ 3 #define SRT_CMD_KMRSP 4 #define SRT_CMD_SID 5 -#define SRT_CMD_CONJESTCTRL 6 +#define SRT_CMD_CONGESTION 6 +#define SRT_CMD_FILTER 7 +#define SRT_CMD_GROUP 8 enum SrtDataStruct { @@ -214,9 +251,7 @@ enum UDTRequestType URQ_WAVEAHAND = 0, URQ_INDUCTION = 1, - URQ_FAILURE_TYPES = 1000, - URQ_REJECT = 1002, - URQ_INVALID = 1004 + URQ_FAILURE_TYPES = 1000 }; @@ -230,31 +265,41 @@ enum SRT_KM_STATE }; static const value_string srt_ctrlmsg_types[] = { - {UMSG_HANDSHAKE, "UMSG_HANDSHAKE"}, - {UMSG_KEEPALIVE, "UMSG_KEEPALIVE"}, - {UMSG_ACK, "UMSG_ACK"}, - {UMSG_LOSSREPORT, "UMSG_LOSSREPORT"}, - {UMSG_CGWARNING, "UMSG_CGWARNING"}, - {UMSG_SHUTDOWN, "UMSG_SHUTDOWN"}, - {UMSG_ACKACK, "UMSG_ACKACK"}, - {UMSG_DROPREQ, "UMSG_DROPREQ"}, - {UMSG_PEERERROR, "UMSG_PEERERROR"}, - {UMSG_EXT, "UMSG_EXT"}, + {UMSG_HANDSHAKE, "HANDSHAKE"}, + {UMSG_KEEPALIVE, "KEEPALIVE"}, + {UMSG_ACK, "ACK"}, + {UMSG_LOSSREPORT, "LOSSREPORT"}, + {UMSG_CGWARNING, "CGWARNING"}, + {UMSG_SHUTDOWN, "SHUTDOWN"}, + {UMSG_ACKACK, "ACKACK"}, + {UMSG_DROPREQ, "DROPREQ"}, + {UMSG_PEERERROR, "PEERERROR"}, + {UMSG_EXT, "EXT"}, {0, NULL}, }; static const value_string srt_ctrlmsg_exttypes[] = { - {SRT_CMD_HSREQ, "SRT_CMD_HSREQ"}, - {SRT_CMD_HSRSP, "SRT_CMD_HSRSP"}, - {SRT_CMD_KMREQ, "SRT_CMD_KMREQ"}, - {SRT_CMD_KMRSP, "SRT_CMD_KMRSP"}, - {SRT_CMD_SID, "SRT_CMD_SID"}, - {SRT_CMD_CONJESTCTRL, "SRT_CMD_CONJESTCTRL"}, + {SRT_CMD_HSREQ, "HSREQ"}, + {SRT_CMD_HSRSP, "HSRSP"}, + {SRT_CMD_KMREQ, "KMREQ"}, + {SRT_CMD_KMRSP, "KMRSP"}, + {SRT_CMD_SID, "SID"}, + {SRT_CMD_CONGESTION, "CONGESTION"}, + {SRT_CMD_FILTER, "FILTER"}, + {SRT_CMD_GROUP, "GROUP"}, { 0, NULL }, }; +static const value_string srt_hs_ext_group_type[] = { + { 0, "Undefined" }, + { 1, "Broadcast" }, + { 2, "Main/Backup" }, + { 3, "Balancing"}, + { 0, NULL } +}; + static const value_string srt_hsv4_socket_types[] = { {SRT_STREAM, "SRT_STREAM"}, {SRT_DGRAM, "SRT_DGRAM"}, @@ -286,8 +331,8 @@ static const value_string srt_pb_types[] = { static const value_string srt_msgno_enctypes[] = { {SRT_MSGNO_EK_NONE, "Not encrypted"}, - {SRT_MSGNO_EK_EVEN, "Encrypted ith even key"}, - {SRT_MSGNO_EK_ODD, "Encrypted with odd key"}, + {SRT_MSGNO_EK_EVEN, "Encrypted (even key)"}, + {SRT_MSGNO_EK_ODD, "Encrypted (odd key)"}, {0, NULL}, }; @@ -301,8 +346,6 @@ static const value_string srt_hs_request_types[] = { {URQ_CONCLUSION, "URQ_CONCLUSION"}, {URQ_WAVEAHAND, "URQ_WAVEAHAND (rendezvous invocation)"}, {URQ_AGREEMENT, "URQ_AGREEMENT (rendezvous finalization)"}, - {URQ_REJECT, "!REJECT"}, - {URQ_INVALID, "!INVALID"}, {0, NULL} }; @@ -344,15 +387,15 @@ static void srt_format_ip_address(gchar* dest, size_t dest_size, const gchar* pt { for (i = 4; i < 16; ++i) { - if ( ptr[i] == 0 ) + if (ptr[i] == 0) continue; /* This is not an IP4 */ - p = (guint32*) &ia6; + p = (guint32*)&ia6; for (j = 0; j < 4; ++j) p[j] = g_ntohl(((guint32*)ptr)[j]); - ws_inet_ntop6(&ia6, dest, (guint) dest_size); + ws_inet_ntop6(&ia6, dest, (guint)dest_size); return; } } @@ -364,7 +407,7 @@ static void srt_format_ip_address(gchar* dest, size_t dest_size, const gchar* pt // Here's IPv4, so invert only one l. ia4 = g_ntohl(*((const guint32*)ptr)); - ws_inet_ntop4(&ia4, dest, (guint) dest_size); + ws_inet_ntop4(&ia4, dest, (guint)dest_size); return; } @@ -392,10 +435,97 @@ static void srt_format_hs_ext_hsreq(proto_tree* tree, tvbuff_t* tvb, int baseoff }; proto_tree_add_bitmask_with_flags(tree, tvb, baseoff + 4, hf_srt_handshake_ext_flags, - ett_srt_handshake_ext_flags, ext_hs_flags, ENC_NA, BMT_NO_APPEND); + ett_srt_handshake_ext_flags, ext_hs_flags, ENC_NA, BMT_NO_APPEND); + + proto_tree_add_item(tree, hf_srt_srths_peer_latency, tvb, baseoff + 8, 2, ENC_BIG_ENDIAN); + proto_tree_add_item(tree, hf_srt_srths_agent_latency, tvb, baseoff + 10, 2, ENC_BIG_ENDIAN); +} + +static void srt_format_km(proto_tree* tree, tvbuff_t* tvb, int baseoff, int blocklen) +{ + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |S| V | PT | Sign | Resv1 | KK| + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | KEKI | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Cipher | Auth | SE | Resv2 | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Resv3 | SLen/4 | KLen/4 | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Salt | + // | (16 bytes) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // + Wrapped Key + + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + guint u8bits = 0; + guint32 slen = 0; + + proto_tree_add_item(tree, hf_srt_km_s, tvb, baseoff, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(tree, hf_srt_km_v, tvb, baseoff, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(tree, hf_srt_km_pt, tvb, baseoff, 1, ENC_BIG_ENDIAN); + + proto_tree_add_item(tree, hf_srt_km_sign, tvb, baseoff + 1, 2, ENC_NA); + + proto_tree_add_item(tree, hf_srt_km_resv1, tvb, baseoff + 3, 1, ENC_NA); + + const value_string kk_desc[] = { + { 0, "No SEK is provided - invalid KM" }, + { 1, "Even key is provided" }, + { 2, "Odd key is provided" }, + { 3, "Both even and odd keys are provided"}, + { 0, NULL } + }; + + u8bits = tvb_get_guint8(tvb, baseoff + 3); + proto_tree_add_uint_format_value(tree, hf_srt_km_kk, tvb, baseoff + 3, 1, + u8bits, "%u (%s)", (u8bits & SRT_KM_KK_MASK), try_val_to_str(u8bits & SRT_KM_KK_MASK, kk_desc)); + + const value_string cipher_desc[] = { + { 0, "None or KEKI indexed crypto context" }, + { 1, "AES-ECB (reserved, not supported)" }, + { 2, "AES-CTR" }, + { 3, "AES-CBC (reserved, not supported)" }, + { 4, "AES-GCM" }, + { 0, NULL } + }; + proto_tree_add_item(tree, hf_srt_km_keki, tvb, baseoff + 4, 4, ENC_BIG_ENDIAN); + + u8bits = tvb_get_guint8(tvb, baseoff + 8); + proto_tree_add_uint_format_value(tree, hf_srt_km_cipher, tvb, baseoff + 8, 1, + u8bits, "%u (%s)", u8bits, try_val_to_str(u8bits, cipher_desc)); - proto_tree_add_item(tree, hf_srt_srths_peer_latency, tvb, baseoff+8, 2, ENC_BIG_ENDIAN); - proto_tree_add_item(tree, hf_srt_srths_agent_latency, tvb, baseoff+10, 2, ENC_BIG_ENDIAN); + proto_tree_add_item(tree, hf_srt_km_auth, tvb, baseoff + 9, 1, ENC_BIG_ENDIAN); + + const value_string se_desc[] = { + { 0, "Unspecified" }, + { 1, "MPEG2-TS/UDP" }, + { 2, "MPEG2-TS/SRT" }, + { 0, NULL } + }; + u8bits = tvb_get_guint8(tvb, baseoff + 10); // km.se + proto_tree_add_uint_format_value(tree, hf_srt_km_se, tvb, baseoff + 10, 1, + u8bits, "%u (%s)", u8bits, try_val_to_str(u8bits, se_desc)); + + proto_tree_add_item(tree, hf_srt_km_resv2, tvb, baseoff + 11, 1, ENC_NA); + proto_tree_add_item(tree, hf_srt_km_resv3, tvb, baseoff + 12, 2, ENC_NA); + + u8bits = tvb_get_guint8(tvb, baseoff + 14); // km.slen + slen = 4 * u8bits; + proto_tree_add_uint_format_value(tree, hf_srt_km_slen, tvb, baseoff + 14, 1, + u8bits, "%u (%d bytes)", u8bits, slen); + + u8bits = tvb_get_guint8(tvb, baseoff + 15); // km.klen + proto_tree_add_uint_format_value(tree, hf_srt_km_klen, tvb, baseoff + 15, 1, + u8bits, "%u (%d bytes)", u8bits, 4 * u8bits); + + proto_tree_add_item(tree, hf_srt_km_salt, tvb, baseoff + 16, slen, ENC_NA); + + const int wrap_offset = 16 + slen; + proto_tree_add_item(tree, hf_srt_km_wrap, tvb, baseoff + wrap_offset, blocklen - wrap_offset, ENC_NA); } static void srt_format_kmx(proto_tree* tree, tvbuff_t* tvb, int baseoff, int blocklen) @@ -407,7 +537,35 @@ static void srt_format_kmx(proto_tree* tree, tvbuff_t* tvb, int baseoff, int blo } else { - proto_tree_add_item(tree, hf_srt_srtkm_msg, tvb, baseoff, blocklen, ENC_NA); + srt_format_km(tree, tvb, baseoff, blocklen); + } +} + +static void srt_format_hs_ext_group(proto_tree* tree, tvbuff_t* tvb, packet_info* pinfo, int baseoff, int blocklen) +{ + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Group ID | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Type | Flags | Weight | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + if (blocklen < 8) + { + proto_tree_add_expert_format(tree, pinfo, &ei_srt_hs_ext_hsreq_len, + tvb, baseoff, blocklen, "Actual length is %u", blocklen); + return; + } + + proto_tree_add_item(tree, hf_srt_hs_ext_group_id, tvb, baseoff, 4, ENC_BIG_ENDIAN); + proto_tree_add_item(tree, hf_srt_hs_ext_group_type, tvb, baseoff + 4, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(tree, hf_srt_hs_ext_group_flags, tvb, baseoff + 5, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(tree, hf_srt_hs_ext_group_weight, tvb, baseoff + 6, 2, ENC_BIG_ENDIAN); + + if (blocklen > 8) + { + proto_tree_add_expert_format(tree, pinfo, &ei_srt_hs_ext_hsreq_len, + tvb, baseoff, blocklen, "Actual length is %u", blocklen); } } @@ -440,17 +598,64 @@ static void dissect_srt_hs_ext_field(proto_tree* tree, } -static void format_text_reorder_32(proto_tree* tree, tvbuff_t* tvb, int hfinfo, int baseoff, int blocklen) +/* + * UTF-8 string packed as 32 bit little endian words (what?!) + * https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01#section-3.2.1.3 + * + * THe spec says + * + * The actual size is determined by the Extension Length field, + * which defines the length in four byte blocks. If the actual + * payload is less than the declared length, the remaining bytes + * are set to zeros. + * + * The content is stored as 32-bit little endian words. + * + * This means that the octets of the string are in the rather peculiar + * order: + * + * octet 3 + * octet 2 + * octet 1 + * octet 0 + * octet 8 + * octet 7 + * octet 6 + * octet 5 + * + * and so on, with null padding (not null termination). + */ +static void format_text_reorder_32(proto_tree* tree, tvbuff_t* tvb, packet_info *pinfo, int hfinfo, int baseoff, int blocklen) { - wmem_strbuf_t *sid = wmem_strbuf_new(wmem_packet_scope(), ""); + wmem_strbuf_t *sid = wmem_strbuf_create(pinfo->pool); for (int ii = 0; ii < blocklen; ii += 4) { + // + // Yes, this is fetching the 32-bit word as big-endian + // rather than little-endian. + // + // However, it's then taking the low-order byte of the + // result as the first octet, followed by the byte above + // that, followed by the byte above that, followed by + // the high-order byte. + // + // This is equivalent t fetching the 32-bit word as little-endian + // and then taking the high-order byte of the result as the + // first octet, etc. + // + // And both of those implement what's described above. + // + // No, I have no idea why they chose this representation for + // strings. + // const guint32 u = tvb_get_ntohl(tvb, baseoff + ii); wmem_strbuf_append_c(sid, 0xFF & (u >> 0)); wmem_strbuf_append_c(sid, 0xFF & (u >> 8)); wmem_strbuf_append_c(sid, 0xFF & (u >> 16)); wmem_strbuf_append_c(sid, 0xFF & (u >> 24)); } + if (!wmem_strbuf_utf8_validate(sid, NULL)) + wmem_strbuf_utf8_make_valid(sid); proto_tree_add_string(tree, hfinfo, tvb, baseoff, blocklen, wmem_strbuf_get_str(sid)); } @@ -479,26 +684,26 @@ dissect_srt_control_packet(tvbuff_t *tvb, packet_info* pinfo, switch (type) { case UMSG_EXT: - col_add_fstr(pinfo->cinfo, COL_INFO, "Control/ext: %s socket: 0x%x", + col_add_fstr(pinfo->cinfo, COL_INFO, "Control/ext: %s socket: %d", val_to_str(exttype, srt_ctrlmsg_exttypes, - "Unknown SRT Control Type (0x%x)"), + "Unknown EXT Control Type (%d)"), tvb_get_ntohl(tvb, 12)); break; case UMSG_ACK: - col_add_fstr(pinfo->cinfo, COL_INFO, "Control: UMSG_ACK %d ackseq: %d socket: 0x%x", + col_add_fstr(pinfo->cinfo, COL_INFO, "Control: ACK %d seqno: %u socket: %d", tvb_get_ntohl(tvb, 4), tvb_get_ntohl(tvb, 16), tvb_get_ntohl(tvb, 12)); break; case UMSG_ACKACK: - col_add_fstr(pinfo->cinfo, COL_INFO, "Control: UMSG_ACKACK %d socket: 0x%x", + col_add_fstr(pinfo->cinfo, COL_INFO, "Control: ACKACK %d socket: %d", tvb_get_ntohl(tvb, 4), tvb_get_ntohl(tvb, 12)); break; default: - col_add_fstr(pinfo->cinfo, COL_INFO, "Control: %s socket: 0x%x", + col_add_fstr(pinfo->cinfo, COL_INFO, "Control: %s socket: %d", val_to_str(type, srt_ctrlmsg_types, - "Unknown UDT Control Type (%x)"), + "Unknown Control Type (%d)"), tvb_get_ntohl(tvb, 12)); break; } @@ -533,6 +738,7 @@ dissect_srt_control_packet(tvbuff_t *tvb, packet_info* pinfo, const int version = tvb_get_ntohl(tvb, 16); const int final_length = tvb_reported_length(tvb); int baselen = 64; + int handshake_reqtype; /* This contains the handshake version (currently 4 or 5) */ proto_tree_add_item(tree, hf_srt_handshake_version, tvb, @@ -566,14 +772,51 @@ dissect_srt_control_packet(tvbuff_t *tvb, packet_info* pinfo, 28, 4, ENC_BIG_ENDIAN); proto_tree_add_item(tree, hf_srt_handshake_flow_window, tvb, 32, 4, ENC_BIG_ENDIAN); - proto_tree_add_item(tree, hf_srt_handshake_reqtype, tvb, + handshake_reqtype = tvb_get_ntohl(tvb, 36); + if (handshake_reqtype < URQ_FAILURE_TYPES) + { + proto_tree_add_item(tree, hf_srt_handshake_reqtype, tvb, 36, 4, ENC_BIG_ENDIAN); + } + else + { + static const range_string rej_codes_rvals[] = { + { 0, 0, "REJ_UNKNOWN" }, + { 1, 1, "REJ_SYSTEM" }, + { 2, 2, "REJ_PEER" }, + { 3, 3, "REJ_RESOURCE" }, + { 4, 4, "REJ_ROGUE" }, + { 5, 5, "REJ_BACKLOG" }, + { 6, 6, "REJ_IPE" }, + { 7, 7, "REJ_CLOSE" }, + { 8, 8, "REJ_VERSION" }, + { 9, 9, "REJ_RDVCOOKIE" }, + { 10, 10, "REJ_BADSECRET" }, + { 11, 11, "REJ_UNSECURE" }, + { 12, 12, "REJ_MESSAGEAPI" }, + { 13, 13, "REJ_CONGESTION" }, + { 14, 14, "REJ_FILTER" }, + { 15, 15, "REJ_GROUP" }, + { 16, 16, "REJ_TIMEOUT" }, + { 17, 17, "REJ_CRYPTO" }, + { 18, 999, "SRT Internal Rejection Reason"}, + { 1000, 1999, "SRT Predefined Rejection Reason"}, + { 2000, INT32_MAX, "User Defined Rejection Reason"}, + + { 0x00, 0x00, NULL }, + }; + + const int error_code = handshake_reqtype - URQ_FAILURE_TYPES; + proto_tree_add_uint_format_value(tree, hf_srt_handshake_failure_type, tvb, 36, 4, handshake_reqtype, + "%d (%s)", error_code, rval_to_str_const(error_code, rej_codes_rvals, "Unknown")); + } + proto_tree_add_item(tree, hf_srt_handshake_id, tvb, 40, 4, ENC_BIG_ENDIAN); proto_tree_add_item(tree, hf_srt_handshake_cookie, tvb, 44, 4, ENC_BIG_ENDIAN); - srt_format_ip_address(ipbuf, sizeof ipbuf, (const gchar *)tvb_memdup(wmem_packet_scope(), tvb, 48, 16)); + srt_format_ip_address(ipbuf, sizeof ipbuf, (const gchar *)tvb_memdup(pinfo->pool, tvb, 48, 16)); proto_tree_add_string(tree, hf_srt_handshake_peerip, tvb, 48, 16, ipbuf); @@ -621,11 +864,19 @@ dissect_srt_control_packet(tvbuff_t *tvb, packet_info* pinfo, break; case SRT_CMD_SID: - format_text_reorder_32(tree, tvb, hf_srt_srths_sid, begin, 4 * blocklen); + format_text_reorder_32(tree, tvb, pinfo, hf_srt_srths_sid, begin, 4 * blocklen); + break; + + case SRT_CMD_CONGESTION: + format_text_reorder_32(tree, tvb, pinfo, hf_srt_srths_congestcontrol, begin, 4 * blocklen); + break; + + case SRT_CMD_FILTER: + format_text_reorder_32(tree, tvb, pinfo, hf_srt_hs_ext_filter, begin, 4 * blocklen); break; - case SRT_CMD_CONJESTCTRL: - format_text_reorder_32(tree, tvb, hf_srt_srths_conjestcontrol, begin, 4 * blocklen); + case SRT_CMD_GROUP: + srt_format_hs_ext_group(tree, tvb, pinfo, begin, blocklen * 4); break; default: @@ -693,6 +944,21 @@ dissect_srt_control_packet(tvbuff_t *tvb, packet_info* pinfo, } } break; + case UMSG_DROPREQ: + { + guint len = tvb_reported_length(tvb); + if (len > (4 + 0) * 4) + { + guint lo = tvb_get_ntohl(tvb, (4 + 0) * 4); + guint hi = tvb_get_ntohl(tvb, (4 + 1) * 4); + + proto_tree_add_expert_format(tree, pinfo, &ei_srt_nak_seqno, + tvb, 16, 8, "Drop sequence range: %u-%u", + lo, hi); + proto_item_set_len(srt_item, (gint) len); + } + } + break; case UMSG_LOSSREPORT: { guint len = tvb_reported_length(tvb); @@ -796,10 +1062,11 @@ dissect_srt_udp(tvbuff_t *tvb, packet_info* pinfo, proto_tree *parent_tree, tvbuff_t *next_tvb; col_add_fstr(pinfo->cinfo, COL_INFO, - "DATA: seqno: %u msgno: %u socket: 0x%x", + "DATA: seqno: %u msgno: #%u socket: %d %s", tvb_get_ntohl(tvb, 0), tvb_get_ntohl(tvb, 4) & SRT_MSGNO_MSGNO_MASK, - tvb_get_ntohl(tvb, 12)); + tvb_get_ntohl(tvb, 12), + tvb_get_ntohl(tvb, 4) & SRT_MSGNO_REXMIT_FLG ? "R" : ""); if (tree) { @@ -929,7 +1196,7 @@ void proto_register_srt(void) {&hf_srt_id, { "Destination Socket ID", "srt.id", - FT_UINT32, BASE_HEX, + FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL}}, {&hf_srt_ack_seqno, { @@ -984,7 +1251,7 @@ void proto_register_srt(void) HFILL}}, {&hf_srt_handshake_enc_field_v5, { - "Encryption Field", "srt.hs.encfield", + "Crypto Key Field", "srt.hs.enckeyfield", FT_UINT16, BASE_HEX, VALS(srt_handshake_enc_field), 0, NULL, HFILL}}, @@ -1036,15 +1303,21 @@ void proto_register_srt(void) FT_INT32, BASE_DEC, VALS(srt_hs_request_types), 0, NULL, HFILL}}, + {&hf_srt_handshake_failure_type, { + "Handshake FAILURE code", "srt.hs.failtype", + FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL}}, + {&hf_srt_handshake_id, { "Socket ID", "srt.hs.id", - FT_UINT32, BASE_HEX, + FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL}}, {&hf_srt_handshake_cookie, { "SYN Cookie", "srt.hs.cookie", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL}}, + {&hf_srt_handshake_peerip, { /* FT_STRINGZ is used because the value * is formatted to a temporary buffer first */ @@ -1148,10 +1421,134 @@ void proto_register_srt(void) FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL}}, - {&hf_srt_srths_conjestcontrol, { - "Congestion Control Type", "srt.hs.conjestctrl", + {&hf_srt_srths_congestcontrol, { + "Congestion Control Type", "srt.hs.congestctrl", + FT_STRING, BASE_NONE, + NULL, 0, NULL, HFILL}}, + + {&hf_srt_hs_ext_filter, { + "Packet Filter Type", "srt.hs.filter", FT_STRING, BASE_NONE, + NULL, 0, NULL, HFILL}}, + + {&hf_srt_km, { + "Key Material", "srt.km", + FT_BYTES, BASE_NONE, + NULL, 0, NULL, HFILL}}, + + {&hf_srt_km_s, { + "Reserved 'S' Bit", "srt.km.s", + FT_UINT8, BASE_DEC, NULL, + SRT_KM_S_MASK, NULL, HFILL}}, + + {&hf_srt_km_v, { + "KM Version", "srt.km.v", + FT_UINT8, BASE_DEC, + NULL, SRT_KM_V_MASK, NULL, + HFILL} }, + + {&hf_srt_km_pt, { + "KM Payload Type", "srt.km.pt", + FT_UINT8, BASE_DEC, + NULL, SRT_KM_PT_MASK, NULL, + HFILL} }, + + {&hf_srt_km_sign, { + "KM Signature", "srt.km.sign", + FT_BYTES, BASE_NONE, + NULL, 0, NULL, + HFILL} }, + + {&hf_srt_km_resv1, { + "Reserved1", "srt.km.resv1", + FT_UINT8, BASE_DEC, + NULL, SRT_KM_RESV1_MASK, NULL, + HFILL} }, + + {&hf_srt_km_kk, { + "Encryption Keys", "srt.km.kk", + FT_UINT8, BASE_DEC, + NULL, SRT_KM_KK_MASK, NULL, + HFILL} }, + + {&hf_srt_km_keki, { + "KEK index", "srt.km.keki", + FT_UINT32, BASE_DEC, + NULL, 0, NULL, + HFILL} }, + + {&hf_srt_km_cipher, { + "Cipher", "srt.km.cipher", + FT_UINT8, BASE_DEC, + NULL, 0, NULL, + HFILL} }, + + {&hf_srt_km_auth, { + "Auth", "srt.km.auth", + FT_UINT8, BASE_DEC, + NULL, 0, NULL, + HFILL} }, + + {&hf_srt_km_se, { + "Stream Encapsulation", "srt.km.se", + FT_UINT8, BASE_DEC, + NULL, 0, NULL, + HFILL} }, + + {&hf_srt_km_resv2, { + "Reserved2", "srt.km.resv2", + FT_UINT8, BASE_DEC, + NULL, 0, NULL, + HFILL} }, + + { &hf_srt_km_resv3, { + "Reserved3", "srt.km.resv3", + FT_UINT16, BASE_DEC, + NULL, 0, NULL, + HFILL} }, + + {&hf_srt_km_slen, { + "Salt Length (4-byte blocks)", "srt.km.slen", + FT_UINT8, BASE_DEC, + NULL, 0, NULL, + HFILL} }, + + {&hf_srt_km_klen, { + "SEK Length (4-byte blocks)", "srt.km.klen", + FT_UINT8, BASE_DEC, + NULL, 0, NULL, + HFILL} }, + + {&hf_srt_km_salt, { + "Salt", "srt.km.salt", + FT_BYTES, BASE_NONE, + NULL, 0, NULL, HFILL}}, + + {&hf_srt_km_wrap, { + "Key wrap", "srt.km.wrap", + FT_BYTES, BASE_NONE, + NULL, 0, NULL, HFILL}}, + + {&hf_srt_hs_ext_group_id, { + "Group ID", "srt.hs_ext_group.id", + FT_UINT32, BASE_DEC, + NULL, 0, NULL, HFILL}}, + + { &hf_srt_hs_ext_group_type, { + "Group Type", "srt.hs_ext_group.type", + FT_UINT8, BASE_DEC, + VALS(srt_hs_ext_group_type), 0, NULL, HFILL}}, + + { &hf_srt_hs_ext_group_flags, { + "Group Flags", "srt.hs_ext_group.flags", + FT_UINT8, BASE_DEC, + NULL, 0, NULL, HFILL}}, + + { &hf_srt_hs_ext_group_weight, { + "Member Weight", "srt.hs_ext_group.member_weight", + FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL}} + }; static gint *ett[] = { @@ -1172,6 +1569,10 @@ void proto_register_srt(void) { &ei_srt_hs_ext_type, { "srt.hs.ext.type", PI_PROTOCOL, PI_WARN, "Unknown HS Ext Type", EXPFILL }}, + + { &ei_srt_hs_ext_group_len, + { "srt.hs.ext.group", PI_PROTOCOL, PI_WARN, + "Wrong HS Ext Group length", EXPFILL }}, }; proto_srt = proto_register_protocol("SRT Protocol", "SRT", "srt"); @@ -1181,14 +1582,12 @@ void proto_register_srt(void) expert_srt = expert_register_protocol(proto_srt); expert_register_field_array(expert_srt, ei, array_length(ei)); - register_dissector("srt", dissect_srt_udp, proto_srt); + srt_udp_handle = register_dissector("srt", dissect_srt_udp, proto_srt); } void proto_reg_handoff_srt(void) { - srt_udp_handle = create_dissector_handle(dissect_srt_udp, proto_srt); - /* register as heuristic dissector for UDP */ heur_dissector_add("udp", dissect_srt_heur_udp, "SRT over UDP", "srt_udp", proto_srt, HEURISTIC_ENABLE); |