2 * Routines for SAP HDB (HANA SQL Command Network Protocol) dissection
3 * Copyright 2022, Martin Gallo <martin.gallo [AT] gmail.com>
4 * Code contributed by SecureAuth Corp.
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
14 * This is a dissector that partially implements the HDB protocol. Reference of the protocol can be found in SAP's official documentation:
15 * https://help.sap.com/viewer/7e4aba181371442d9e4395e7ff71b777/2.0.03/en-US/d5b80175490741adbf1a1ba5ec8f2695.html
17 * and the blog series SecureAuth published around the topic "Exploring the SAP HANA SQL Command Network Protocol":
18 * - Protocol Basics and Authentication: https://www.secureauth.com/blog/exploring-sap-hana-sql-command-network-protocol-protocol-basics-and-authentication/
19 * - Password-based Authentication and TLS: https://www.secureauth.com/blog/exploring-sap-hana-sql-command-network-protocol-password-based-authentication-and-tls/
20 * - Federated Authentication: https://www.secureauth.com/blog/exploring-the-sap-hana-sql-command-network-protocol-federated-authentication/
25 #include <epan/packet.h>
26 #include <epan/prefs.h>
27 #include <epan/expert.h>
28 #include <wsutil/wmem/wmem.h>
29 #include <epan/wmem_scopes.h>
31 #include "packet-tcp.h"
32 #include "packet-tls.h"
36 * Define default ports. The right range should be 3NN13 and 3NN15, but as port numbers are proprietary and not
37 * IANA assigned, we leave only the ones corresponding to the instance 00.
39 #define SAPHDB_PORT_RANGE "30013,30015"
42 #define SAPHDB_HEADER_LEN 32
44 /* SAP HDB Packet Options values */
45 static const value_string saphdb_message_header_packetoptions_vals
[] = {
46 { 0, "Uncompressed" },
52 /* SAP HDB Segment Kind values */
53 static const value_string saphdb_segment_segmentkind_vals
[] = {
62 /* SAP HDB Segment Message Type values */
63 static const value_string saphdb_segment_messagetype_vals
[] = {
65 { 2, "EXECUTEDIRECT" },
76 { 65, "AUTHENTICATE" },
80 { 69, "CLOSERESULTSET" },
81 { 70, "DROPSTATEMENTID" },
83 { 72, "FETCHABSOLUTE" },
84 { 73, "FETCHRELATIVE" },
88 { 78, "EXECUTEITAB" },
89 { 79, "FETCHNEXTITAB" },
90 { 80, "INSERTNEXTITAB" },
91 { 81, "BATCHPREPARE" },
92 { 82, "DBCONNECTINFO" },
93 { 83, "XOPEN_XASTART" },
94 { 84, "XOPEN_XAEND" },
95 { 85, "XOPEN_XAPREPARE" },
96 { 86, "XOPEN_XACOMMIT" },
97 { 87, "XOPEN_XAROLLBACK" },
98 { 88, "XOPEN_XARECOVER" },
99 { 89, "XOPEN_XAFORGET" },
104 /* SAP HDB Segment Function Code values */
105 static const value_string saphdb_segment_functioncode_vals
[] = {
112 { 6, "SELECTFORUPDATE" },
114 { 8, "DBPROCEDURECALL" },
115 { 9, "DBPROCEDURECALLWITHRESULT" },
124 { 18, "DISCONNECT" },
125 { 19, "CLOSECURSOR" },
127 { 21, "ABAPSTREAM" },
131 { 25, "XOPEN_XACONTROL" },
132 { 26, "XOPEN_XAPREPARE" },
133 { 27, "XOPEN_XARECOVER" },
139 /* SAP HDB Part Kind values */
140 static const value_string saphdb_part_partkind_vals
[] = {
145 { 10, "STATEMENTID" },
146 { 11, "TRANSACTIONID" },
147 { 12, "ROWSAFFECTED" },
148 { 13, "RESULTSETID" },
149 { 15, "TOPOLOGYINFORMATION" },
150 { 16, "TABLELOCATION" },
151 { 17, "READLOBREQUEST" },
152 { 18, "READLOBREPLY" },
153 { 25, "ABAPISTREAM" },
154 { 26, "ABAPOSTREAM" },
155 { 27, "COMMANDINFO" },
156 { 28, "WRITELOBREQUEST" },
157 { 29, "CLIENTCONTEXT" },
158 { 30, "WRITELOBREPLY" },
159 { 32, "PARAMETERS" },
160 { 33, "AUTHENTICATION" },
161 { 34, "SESSIONCONTEXT" },
164 { 39, "STATEMENTCONTEXT" },
165 { 40, "PARTITIONINFORMATION" },
166 { 41, "OUTPUTPARAMETERS" },
167 { 42, "CONNECTOPTIONS" },
168 { 43, "COMMITOPTIONS" },
169 { 44, "FETCHOPTIONS" },
171 { 47, "PARAMETERMETADATA" },
172 { 48, "RESULTSETMETADATA" },
173 { 49, "FINDLOBREQUEST" },
174 { 50, "FINDLOBREPLY" },
176 { 53, "ITABCHUNKMETADATA" },
177 { 55, "ITABMETADATA" },
178 { 56, "ITABRESULTCHUNK" },
179 { 57, "CLIENTINFO" },
180 { 58, "STREAMDATA" },
181 { 59, "OSTREAMRESULT" },
182 { 60, "FDAREQUESTMETADATA" },
183 { 61, "FDAREPLYMETADATA" },
184 { 62, "BATCHPREPARE" },
185 { 63, "BATCHEXECUTE" },
186 { 64, "TRANSACTIONFLAGS" },
187 { 65, "ROWSLOTIMAGEPARAMMETADATA" },
188 { 66, "ROWSLOTIMAGERESULTSET" },
189 { 67, "DBCONNECTINFO" },
191 { 69, "RESULTSETOPTIONS" },
192 { 70, "XATRANSACTIONINFO" },
193 { 71, "SESSIONVARIABLE" },
194 { 72, "WORKLOADREPLAYCONTEXT" },
195 { 73, "SQLREPLYOTIONS" },
201 /* SAP HDB Type values */
202 static const value_string saphdb_part_type_vals
[] = {
222 { 19, "TIMESTAMP_TZ" },
223 { 20, "TIMESTAMP_LTZ" },
224 { 21, "INTERVAL_YM" },
225 { 22, "INTERVAL_DS" },
237 { 34, "DECIMAL_DIGIT_ARRAY" },
241 { 38, "VARBINARY3" },
243 { 40, "TINYINT_NOTNULL" },
244 { 41, "SMALLINT_NOTNULL" },
245 { 42, "INT_NOTNULL" },
246 { 43, "BIGINT_NOTNULL" },
250 { 47, "SMALLDECIMAL" },
251 { 48, "ABAPSTREAM" },
252 { 49, "ABAPSTRUCT" },
256 { 53, "FIXEDSTRING" },
257 { 54, "FIXEDPOINTDECIMAL" },
261 { 62, "SECONDDATE" },
263 { 64, "SECONDTIME" },
268 { 73, "NCLOB_DISK" },
272 { 77, "BLOB_HYBRID" },
273 { 78, "CLOB_HYBRID" },
274 { 79, "NCLOB_HYBRID" },
280 /* SAP HDB Error Level values */
281 static const value_string saphdb_error_level_vals
[] = {
290 /* Structure to define Option Parts */
291 typedef struct _option_part_definition
{
293 const char *identifier_strptr
;
295 } option_part_definition
;
298 static const option_part_definition saphdb_part_connect_options_vals
[] = {
299 { 1, "Connection ID", 3 },
300 { 2, "Complete Array Execution", 28 },
301 { 3, "Client Locale", 29 },
302 { 4, "Supports Large Bulk Operations", 28 },
303 { 5, "Distribution Enabled", 28 },
304 { 6, "Primary Connection ID", 0 },
305 { 7, "Primary Connection Host", 0 },
306 { 8, "Primary Connection Port", 0 },
307 { 9, "Complete Data Type Support", 0 },
308 { 10, "Large Number of Parameters Support", 28 },
309 { 11, "System ID", 29 },
310 { 12, "Data Format Version", 3 },
311 { 13, "ABAP VARCHAR Mode", 28 },
312 { 14, "Select for Update Supported", 28 },
313 { 15, "Client Distribution Mode", 3 },
314 { 16, "Engine Data Format Version", 3 },
315 { 17, "Distribution Protocol Version", 3 },
316 { 18, "Split Batch Commands", 28 },
317 { 19, "Use Transaction Flags Only", 28 },
318 { 20, "Row and Column Optimized Format", 28 },
319 { 21, "Ignore Unknown Parts", 3 },
320 { 22, "Table Output Parameter", 28 },
321 { 23, "Data Format Version 2", 3 },
322 { 24, "ITAB Parameter", 28 },
323 { 25, "Describe Table Output Parameter", 28 },
324 { 26, "Columnar Result Set", 0 }, /* This is BITVECTOR type ??? */
325 { 27, "Scrollable Result Set", 3 },
326 { 28, "Client Info NULL Value Supported", 28 },
327 { 29, "Associated Connection ID", 3 },
328 { 30, "Non-Transactional Prepare", 28 },
329 { 31, "Fast Data Access Enabled", 28 },
330 { 32, "OS User", 29 },
331 { 33, "Row Slot Image Result", 0 }, /* This is BITVECTOR type ??? */
332 { 34, "Endianness", 3 },
333 { 35, "Update Topology Anywhere", 28 },
334 { 36, "Enable Array Type", 28 },
335 { 37, "Implicit LOB Streaming", 28 },
336 { 38, "Cached View Property", 28 },
337 { 39, "X OpenXA Protocol Supported", 28 },
338 { 40, "Master Commit Redirection Supported", 28 },
339 { 41, "Active/Active Protocol Version", 3 },
340 { 42, "Active/Active Connection Origin Site", 3 },
341 { 43, "Query Timeout Supported", 28 },
342 { 44, "Full Version String", 29 },
343 { 45, "Database Name", 29 },
344 { 46, "Build Platform", 3 },
345 { 47, "Implicit XA Session Supported", 28 },
346 { 48, "Client Side Column Encryption Version", 3 },
347 { 49, "Compression Level And Flags", 3 },
348 { 50, "Client Side Re-Execution Supported", 28 },
349 { 51, "Client Reconnect Wait Timeout", 3 },
350 { 52, "Original Anchor Connection ID", 3 },
351 { 53, "Flag Set 1", 3 },
352 { 54, "Topology Network Group", 28 },
353 { 55, "IP Address", 29 },
354 { 56, "LRR Ping Time", 3 },
359 static const option_part_definition saphdb_part_commit_options_vals
[] = {
360 { 1, "Hold Cursors Over Commit", 28 },
365 static const option_part_definition saphdb_part_fetch_options_vals
[] = {
366 { 1, "Result Set Pos", 3 },
371 static const option_part_definition saphdb_part_transaction_flags_vals
[] = {
372 { 0, "Rolled Back", 28 },
373 { 1, "Committed", 28 },
374 { 2, "New Isolation Level", 3 },
375 { 3, "DDL Commit Mode Changed", 28 },
376 { 4, "Write Transaction Started", 28 },
377 { 5, "No Write Transaction Started", 28 },
378 { 6, "Session Closing Transaction Error", 28 },
383 static const option_part_definition saphdb_part_topology_info_vals
[] = {
384 { 1, "Host Name", 29 },
385 { 2, "Host Port Number", 3 },
386 { 3, "Tenant Name", 29 },
387 { 4, "Load Factor", 7 },
388 { 5, "Site Volume ID", 3 },
389 { 6, "Is Master", 28 },
390 { 7, "Is Current Session", 28 },
391 { 8, "Service Type", 3 },
392 { 9, "Network Domain", 29 },
393 { 10, "Is Stand-By", 28 },
394 { 11, "All IP Addresses", 29 },
395 { 12, "All Host Names", 29 },
396 { 13, "Site Type", 3 },
401 static const option_part_definition saphdb_part_command_info_vals
[] = {
402 { 1, "Line Number", 3 },
403 { 2, "Source Module", 29 },
408 static const option_part_definition saphdb_part_client_context_vals
[] = {
409 { 1, "Client Version", 29 },
410 { 2, "Client Type", 29 },
411 { 3, "Application Name", 29 },
416 static const option_part_definition saphdb_part_session_context_vals
[] = {
417 { 1, "Primary Connection ID", 3 },
418 { 2, "Primary Host Name", 29 },
419 { 3, "Primary Host Port Number", 3 },
420 { 4, "Master Connection ID", 3 },
421 { 5, "Master Host Name", 29 },
422 { 6, "Master Host Port Number", 3 },
427 static const option_part_definition saphdb_part_statement_context_vals
[] = {
428 { 1, "Statement Sequence Info", 33 },
429 { 2, "Server Processing Time", 4 },
430 { 3, "Schema Name", 29 },
431 { 4, "Flag Set", 8 },
432 { 5, "Query Time Out", 4 },
433 { 6, "Client Reconnection Wait Timeout", 3 },
434 { 7, "Server CPU Time", 4 },
435 { 8, "Server Memory Usage", 4 },
440 static const option_part_definition saphdb_part_dbconnect_info_flags_vals
[] = {
441 { 1, "Database Name", 29 },
444 { 4, "Is Connected", 28 },
449 static const option_part_definition saphdb_part_lob_flags_vals
[] = {
450 { 0, "Implicit Streaming", 28 },
456 static int proto_saphdb
;
458 /* SAP HDB Initialization items */
459 static int hf_saphdb_initialization_request
;
460 static int hf_saphdb_initialization_reply
;
461 static int hf_saphdb_initialization_reply_product_version_major
;
462 static int hf_saphdb_initialization_reply_product_version_minor
;
463 static int hf_saphdb_initialization_reply_protocol_version_major
;
464 static int hf_saphdb_initialization_reply_protocol_version_minor
;
466 /* SAP HDB Message Header items */
467 static int hf_saphdb_message_header
;
468 static int hf_saphdb_message_header_sessionid
;
469 static int hf_saphdb_message_header_packetcount
;
470 static int hf_saphdb_message_header_varpartlength
;
471 static int hf_saphdb_message_header_varpartsize
;
472 static int hf_saphdb_message_header_noofsegm
;
473 static int hf_saphdb_message_header_packetoptions
;
474 static int hf_saphdb_message_header_compressionvarpartlength
;
475 static int hf_saphdb_message_header_reserved
;
476 /* SAP HDB Message Buffer items */
477 static int hf_saphdb_message_buffer
;
478 static int hf_saphdb_compressed_buffer
;
480 /* SAP HDB Segment items */
481 static int hf_saphdb_segment
;
482 static int hf_saphdb_segment_segmentlength
;
483 static int hf_saphdb_segment_segmentofs
;
484 static int hf_saphdb_segment_noofparts
;
485 static int hf_saphdb_segment_segmentno
;
486 static int hf_saphdb_segment_segmentkind
;
487 static int hf_saphdb_segment_messagetype
;
488 static int hf_saphdb_segment_commit
;
489 static int hf_saphdb_segment_commandoptions
;
490 static int hf_saphdb_segment_functioncode
;
491 static int hf_saphdb_segment_reserved
;
492 /* SAP HDB Segment Buffer items */
493 static int hf_saphdb_segment_buffer
;
495 /* SAP HDB Part items */
496 static int hf_saphdb_part
;
497 static int hf_saphdb_part_partkind
;
498 static int hf_saphdb_part_partattributes
;
499 static int hf_saphdb_part_argumentcount
;
500 static int hf_saphdb_part_bigargumentcount
;
501 static int hf_saphdb_part_bufferlength
;
502 static int hf_saphdb_part_buffersize
;
503 /* SAP HDB Part Buffer items */
504 static int hf_saphdb_part_buffer
;
506 /* SAP HDB Part Buffer Option Part Data items */
507 static int hf_saphdb_part_option_argcount
;
508 static int hf_saphdb_part_option_name
;
509 static int hf_saphdb_part_option_type
;
510 static int hf_saphdb_part_option_length
;
511 static int hf_saphdb_part_option_value
;
512 static int hf_saphdb_part_option_value_bool
;
513 static int hf_saphdb_part_option_value_byte
;
514 static int hf_saphdb_part_option_value_short
;
515 static int hf_saphdb_part_option_value_int
;
516 static int hf_saphdb_part_option_value_bigint
;
517 static int hf_saphdb_part_option_value_string
;
518 static int hf_saphdb_part_option_value_double
;
520 /* SAP HDB Part Buffer COMMAND items */
521 static int hf_saphdb_part_command
;
523 /* SAP HDB Part Buffer ERROR items */
524 static int hf_saphdb_part_error_code
;
525 static int hf_saphdb_part_error_position
;
526 static int hf_saphdb_part_error_text_length
;
527 static int hf_saphdb_part_error_level
;
528 static int hf_saphdb_part_error_sqlstate
;
529 static int hf_saphdb_part_error_text
;
531 /* SAP HDB Part Buffer AUTHENTICATE items */
532 static int hf_saphdb_part_authentication_field_count
;
533 static int hf_saphdb_part_authentication_field_length
;
534 static int hf_saphdb_part_authentication_field_value
;
536 /* SAP HDB Part Buffer CLIENTID items */
537 static int hf_saphdb_part_clientid
;
540 static int ett_saphdb
;
543 /* Global port preference */
544 static range_t
*global_saphdb_port_range
;
548 static expert_field ei_saphdb_compressed_unknown
;
549 static expert_field ei_saphdb_option_part_unknown
;
550 static expert_field ei_saphdb_segments_incorrect_order
;
551 static expert_field ei_saphdb_segments_number_incorrect
;
552 static expert_field ei_saphdb_segment_length
;
553 static expert_field ei_saphdb_buffer_length
;
554 static expert_field ei_saphdb_parts_number_incorrect
;
555 static expert_field ei_saphdb_varpartlenght_incorrect
;
558 /* Global highlight preference */
559 static bool global_saphdb_highlight_items
= true;
562 /* Protocol handle */
563 static dissector_handle_t saphdb_handle
;
564 static dissector_handle_t saphdb_handle_tls
;
565 static dissector_handle_t gssapi_handle
;
568 void proto_reg_handoff_saphdb(void);
569 void proto_register_saphdb(void);
572 /* Option Part Value to Option Part Identifier */
574 opv_to_opi(const int8_t value
, const option_part_definition
*opd
, const char *unknown_str
)
578 while (opd
[i
].identifier_strptr
) {
579 if (opd
[i
].value
== value
) {
580 return opd
[i
].identifier_strptr
;
588 /* Option Part Value to Option Part Type */
590 opv_to_opt(const int8_t value
, const option_part_definition
*opd
)
594 while (opd
[i
].identifier_strptr
) {
595 if (opd
[i
].value
== value
) {
605 dissect_saphdb_part_options_data(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, uint32_t offset
, int16_t argcount
, uint8_t partkind
, const option_part_definition
*definition
)
607 uint32_t parsed_length
= 0;
609 while (argcount
> 0 && tvb_reported_length_remaining(tvb
, offset
+ parsed_length
) > 2) {
610 int8_t option_key
= 0, option_type
= 0;
611 int16_t option_length
= 0;
612 int8_t option_value_byte
= 0;
613 proto_item
*option_type_item
= NULL
;
615 option_key
= tvb_get_int8(tvb
, offset
+ parsed_length
);
616 proto_tree_add_int_format(tree
, hf_saphdb_part_option_name
, tvb
, offset
+ parsed_length
, 1, option_key
,
617 "Option Name: %s (%d)", opv_to_opi(option_key
, definition
, "Unknown"), option_key
);
620 option_type
= tvb_get_int8(tvb
, offset
+ parsed_length
);
621 option_type_item
= proto_tree_add_item(tree
, hf_saphdb_part_option_type
, tvb
, offset
+ parsed_length
, 1, ENC_NA
);
624 if (option_type
!= opv_to_opt(option_key
, definition
)) {
625 if (global_saphdb_highlight_items
){
626 expert_add_info_format(pinfo
, option_type_item
, &ei_saphdb_option_part_unknown
, "Option Type for key %d in part kind %d doesn't match! (expected %d, obtained %d)", option_key
, partkind
, opv_to_opt(option_key
, definition
), option_type
);
630 switch (option_type
) {
632 proto_tree_add_item(tree
, hf_saphdb_part_option_value_byte
, tvb
, offset
+ parsed_length
, 1, ENC_NA
);
636 proto_tree_add_item(tree
, hf_saphdb_part_option_value_short
, tvb
, offset
+ parsed_length
, 2, ENC_LITTLE_ENDIAN
);
640 proto_tree_add_item(tree
, hf_saphdb_part_option_value_int
, tvb
, offset
+ parsed_length
, 4, ENC_LITTLE_ENDIAN
);
644 proto_tree_add_item(tree
, hf_saphdb_part_option_value_bigint
, tvb
, offset
+ parsed_length
, 8, ENC_LITTLE_ENDIAN
);
648 proto_tree_add_item(tree
, hf_saphdb_part_option_value_double
, tvb
, offset
+ parsed_length
, 8, ENC_LITTLE_ENDIAN
);
652 option_value_byte
= tvb_get_int8(tvb
, offset
+ parsed_length
);
653 proto_tree_add_boolean(tree
, hf_saphdb_part_option_value_bool
, tvb
, offset
+ parsed_length
, 1, option_value_byte
);
659 option_length
= tvb_get_int16(tvb
, offset
+ parsed_length
, ENC_LITTLE_ENDIAN
);
660 proto_tree_add_item(tree
, hf_saphdb_part_option_length
, tvb
, offset
+ parsed_length
, 2, ENC_LITTLE_ENDIAN
);
663 if (tvb_reported_length_remaining(tvb
, offset
+ parsed_length
) >= option_length
) {
664 if (option_type
== 29) {
665 /* TODO: This need to be CESU-8 decoded */
666 proto_tree_add_item(tree
, hf_saphdb_part_option_value_string
, tvb
, offset
+ parsed_length
, option_length
, ENC_UTF_8
);
667 parsed_length
+= option_length
;
668 } else if (option_type
== 30) {
669 proto_tree_add_item(tree
, hf_saphdb_part_option_value_string
, tvb
, offset
+ parsed_length
, option_length
, ENC_UTF_8
);
670 parsed_length
+= option_length
;
671 } else if (option_type
== 33) {
672 /* This is binary data, not rendering it as a string */
673 proto_tree_add_item(tree
, hf_saphdb_part_option_value
, tvb
, offset
+ parsed_length
, option_length
, ENC_NA
);
674 parsed_length
+= option_length
;
678 default: // Unknown type, we don't know the length nor how to parse it
679 if (global_saphdb_highlight_items
){
680 expert_add_info_format(pinfo
, option_type_item
, &ei_saphdb_option_part_unknown
, "Option Type %d length unknown", option_type
);
687 return parsed_length
;
691 dissect_saphdb_part_multi_line_options_data(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, uint32_t offset
, int16_t rowcount
, uint8_t partkind
, const option_part_definition
*definition
)
693 uint32_t parsed_length
= 0;
695 /* In Multi-line Option Part, the part's argcount is the number of rows. For each row we need to parse the options. */
696 while (rowcount
> 0 && tvb_reported_length_remaining(tvb
, offset
+ parsed_length
) > 2) {
697 int16_t argcount
= 0;
699 /* First we read the amount of arguments in this row */
700 argcount
= tvb_get_int16(tvb
, offset
+ parsed_length
, ENC_LITTLE_ENDIAN
);
701 proto_tree_add_item(tree
, hf_saphdb_part_option_argcount
, tvb
, offset
+ parsed_length
, 2, ENC_LITTLE_ENDIAN
);
704 /* Now parse the options in the row if there are*/
706 parsed_length
+= dissect_saphdb_part_options_data(tvb
, pinfo
, tree
, offset
+ parsed_length
, argcount
, partkind
, definition
);
712 return parsed_length
;
717 dissect_saphdb_gss_authentication_fields(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, uint32_t offset
)
719 uint8_t field_short_length
, commtype
= 0;
720 uint16_t field_count
= 0, field_length
;
722 /* Parse the field count */
723 field_count
= tvb_get_uint16(tvb
, offset
, ENC_LITTLE_ENDIAN
);
724 proto_tree_add_item(tree
, hf_saphdb_part_authentication_field_count
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
727 for (uint16_t field
= 0; field
< field_count
; field
++) {
729 /* Parse the field length. If the first byte is 0xFF, the length is contained in the next 2 bytes */
730 field_short_length
= tvb_get_uint8(tvb
, offset
);
731 if (field_short_length
== 0xff) {
733 field_length
= tvb_get_uint16(tvb
, offset
, ENC_BIG_ENDIAN
);
734 proto_tree_add_item(tree
, hf_saphdb_part_authentication_field_length
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
737 proto_tree_add_item(tree
, hf_saphdb_part_authentication_field_length
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
739 field_length
= field_short_length
;
742 /* We try then to see if we're dealing with the commtype field (second field and with length 1)
745 if ((field
== 1) && (field_length
== 1))
747 commtype
= tvb_get_uint8(tvb
, offset
);
750 /* If this is the last value of a three field packet, and is one of the commtypes that carries an
751 * SPNEGO structure, we call the GSSAPI dissector. The Kerberos data is extracted in a new TVB.
753 if (((commtype
== 3) || (commtype
== 6)) && (field_count
== 3) && (field
== 2)) {
754 tvbuff_t
*kerberos_tvb
;
755 kerberos_tvb
= tvb_new_subset_length(tvb
, offset
, field_length
);
756 add_new_data_source(pinfo
, kerberos_tvb
, "Kerberos Data");
757 call_dissector(gssapi_handle
, kerberos_tvb
, pinfo
, tree
);
760 /* If not we add the field value in plain */
762 proto_tree_add_item(tree
, hf_saphdb_part_authentication_field_value
, tvb
, offset
, field_length
, ENC_NA
);
765 offset
+= field_length
;
772 dissect_saphdb_part_authentication_fields(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, uint32_t offset
)
774 uint8_t field_short_length
;
775 uint16_t field_count
= 0, field_length
;
776 uint32_t parsed_length
= 0;
778 proto_item
*gss_item
= NULL
;
779 proto_tree
*gss_tree
= NULL
;
783 /* Parse the field count */ /* TODO: Should this match with argcount? */
784 field_count
= tvb_get_uint16(tvb
, offset
, ENC_LITTLE_ENDIAN
);
785 proto_tree_add_item(tree
, hf_saphdb_part_authentication_field_count
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
789 for (uint16_t field
= 0; field
< field_count
; field
++) {
791 /* Parse the field length. If the first byte is 0xFF, the length is contained in the next 2 bytes */
792 field_short_length
= tvb_get_uint8(tvb
, offset
);
793 if (field_short_length
== 0xff) {
796 field_length
= tvb_get_uint16(tvb
, offset
, ENC_BIG_ENDIAN
);
797 proto_tree_add_item(tree
, hf_saphdb_part_authentication_field_length
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
801 proto_tree_add_item(tree
, hf_saphdb_part_authentication_field_length
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
804 field_length
= field_short_length
;
807 /* Add the field value */
808 gss_item
= proto_tree_add_item(tree
, hf_saphdb_part_authentication_field_value
, tvb
, offset
, field_length
, ENC_NA
);
810 /* Check if this is a GSS field so we can parse the remaining fields */
811 if ((((field_count
== 2) && (field
== 0)) || ((field_count
== 3) && (field
== 1))) &&
812 (field_length
== 3) && (tvb_strneql(tvb
, offset
, "GSS", 3) != -1)) {
816 /* If the method is GSS, and this is the last value, we add a new tree and parse the value */
817 if (is_gss
&& field
== field_count
- 1) {
818 proto_item_append_text(gss_item
, ": GSS Token");
819 gss_tree
= proto_item_add_subtree(gss_item
, ett_saphdb
);
820 dissect_saphdb_gss_authentication_fields(tvb
, pinfo
, gss_tree
, offset
);
823 offset
+= field_length
; parsed_length
+= field_length
;
827 return parsed_length
;
832 dissect_saphdb_part_buffer(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, uint32_t offset
, uint32_t length
, int16_t argcount
, uint8_t partkind
, proto_item
*partkind_item
)
834 int32_t error_text_length
= 0;
838 if ((length
> 0) && ((uint32_t)tvb_reported_length_remaining(tvb
, offset
) >= length
)) {
839 proto_tree_add_item(tree
, hf_saphdb_part_command
, tvb
, offset
, length
, ENC_ASCII
);
844 proto_tree_add_item(tree
, hf_saphdb_part_error_code
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
847 proto_tree_add_item(tree
, hf_saphdb_part_error_position
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
850 proto_tree_add_item_ret_int(tree
, hf_saphdb_part_error_text_length
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
, &error_text_length
);
853 proto_tree_add_item(tree
, hf_saphdb_part_error_level
, tvb
, offset
, 1, ENC_NA
);
856 proto_tree_add_item(tree
, hf_saphdb_part_error_sqlstate
, tvb
, offset
, 5, ENC_ASCII
);
860 if ((error_text_length
> 0) && (tvb_reported_length_remaining(tvb
, offset
) >= error_text_length
)) {
861 proto_tree_add_item(tree
, hf_saphdb_part_error_text
, tvb
, offset
, error_text_length
, ENC_ASCII
);
862 length
-= error_text_length
;
864 /* Align the error text length to 8 */
865 if ((error_text_length
% 8) != 0) {
866 length
+= 8 - (error_text_length
% 8);
871 case 33: // AUTHENTICATION
872 dissect_saphdb_part_authentication_fields(tvb
, pinfo
, tree
, offset
);
876 if ((length
> 0) && ((uint32_t)tvb_reported_length_remaining(tvb
, offset
) >= length
)) {
877 proto_tree_add_item(tree
, hf_saphdb_part_clientid
, tvb
, offset
, length
, ENC_ASCII
);
882 // Multi-line Option Parts
883 case 15: // TOPOLOGYINFORMATION
884 dissect_saphdb_part_multi_line_options_data(tvb
, pinfo
, tree
, offset
, argcount
, partkind
, saphdb_part_topology_info_vals
);
888 case 27: // COMMANDINFO
889 dissect_saphdb_part_options_data(tvb
, pinfo
, tree
, offset
, argcount
, partkind
, saphdb_part_command_info_vals
);
891 case 29: // CLIENTCONTEXT
892 dissect_saphdb_part_options_data(tvb
, pinfo
, tree
, offset
, argcount
, partkind
, saphdb_part_client_context_vals
);
894 case 34: // SESSIONCONTEXT
895 dissect_saphdb_part_options_data(tvb
, pinfo
, tree
, offset
, argcount
, partkind
, saphdb_part_session_context_vals
);
897 case 39: // STATEMENTCONTEXT
898 dissect_saphdb_part_options_data(tvb
, pinfo
, tree
, offset
, argcount
, partkind
, saphdb_part_statement_context_vals
);
900 case 42: // CONNECTOPTIONS
901 dissect_saphdb_part_options_data(tvb
, pinfo
, tree
, offset
, argcount
, partkind
, saphdb_part_connect_options_vals
);
903 case 43: // COMMITOPTIONS
904 dissect_saphdb_part_options_data(tvb
, pinfo
, tree
, offset
, argcount
, partkind
, saphdb_part_commit_options_vals
);
906 case 44: // FETCHOPTIONS
907 dissect_saphdb_part_options_data(tvb
, pinfo
, tree
, offset
, argcount
, partkind
, saphdb_part_fetch_options_vals
);
909 case 64: // TRANSACTIONFLAGS
910 dissect_saphdb_part_options_data(tvb
, pinfo
, tree
, offset
, argcount
, partkind
, saphdb_part_transaction_flags_vals
);
912 case 67: // DBCONNECTINFO
913 dissect_saphdb_part_options_data(tvb
, pinfo
, tree
, offset
, argcount
, partkind
, saphdb_part_dbconnect_info_flags_vals
);
916 dissect_saphdb_part_options_data(tvb
, pinfo
, tree
, offset
, argcount
, partkind
, saphdb_part_lob_flags_vals
);
920 if (global_saphdb_highlight_items
){
921 expert_add_info_format(pinfo
, partkind_item
, &ei_saphdb_option_part_unknown
, "Part Kind %d unknown", partkind
);
931 dissect_saphdb_part(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
, uint32_t offset
, int16_t number_of_parts
, uint16_t part_number
)
934 int16_t argcount
= 0;
935 int32_t bufferlength
= 0;
937 proto_item
*part_item
= NULL
, *partkind_item
= NULL
, *part_buffer_length_item
= NULL
, *part_buffer_item
= NULL
;
938 proto_tree
*part_tree
= NULL
, *part_buffer_tree
= NULL
;
940 /* Add the Part subtree */
941 part_item
= proto_tree_add_item(tree
, hf_saphdb_part
, tvb
, offset
, 16, ENC_NA
);
942 part_tree
= proto_item_add_subtree(part_item
, ett_saphdb
);
943 proto_item_append_text(part_item
, " (%d/%d)", part_number
, number_of_parts
);
945 /* Add the Part fields */
946 partkind
= tvb_get_int8(tvb
, offset
);
947 proto_item_append_text(part_item
, ", %s", val_to_str_const(partkind
, saphdb_part_partkind_vals
, "Unknown"));
948 partkind_item
= proto_tree_add_item(part_tree
, hf_saphdb_part_partkind
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
951 proto_tree_add_item(part_tree
, hf_saphdb_part_partattributes
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
954 argcount
= tvb_get_int16(tvb
, offset
, ENC_LITTLE_ENDIAN
);
955 proto_tree_add_item(part_tree
, hf_saphdb_part_argumentcount
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
958 proto_tree_add_item(part_tree
, hf_saphdb_part_bigargumentcount
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
961 part_buffer_length_item
= proto_tree_add_item_ret_int(part_tree
, hf_saphdb_part_bufferlength
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
, &bufferlength
);
964 proto_tree_add_item(part_tree
, hf_saphdb_part_buffersize
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
968 /* Check the length */
969 if (bufferlength
< 0) {
970 expert_add_info_format(pinfo
, part_buffer_length_item
, &ei_saphdb_buffer_length
, "Part Buffer length %d is invalid", bufferlength
);
973 /* Align the buffer length to 8 */
974 if (bufferlength
% 8 != 0) {
975 bufferlength
+= 8 - bufferlength
% 8;
978 /* Adjust the length */
979 if (bufferlength
< 0 || tvb_reported_length_remaining(tvb
, offset
) < bufferlength
) {
980 bufferlength
= tvb_reported_length_remaining(tvb
, offset
);
983 /* Add the part buffer tree and dissect it */
985 part_buffer_item
= proto_tree_add_item(part_tree
, hf_saphdb_part_buffer
, tvb
, offset
, bufferlength
, ENC_NA
);
986 part_buffer_tree
= proto_item_add_subtree(part_buffer_item
, ett_saphdb
);
988 dissect_saphdb_part_buffer(tvb
, pinfo
, part_buffer_tree
, offset
, bufferlength
, argcount
, partkind
, partkind_item
);
989 length
+= bufferlength
;
992 /* Adjust the item tree length */
993 proto_item_set_len(part_tree
, length
);
1000 dissect_saphdb_segment(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
, uint32_t offset
, int16_t number_of_segments
, uint16_t nosegment
, bool compressed
)
1002 int8_t segmentkind
= 0, message_type
= 0;
1003 int16_t number_of_parts
= 0, segment_number
= 0, function_code
= 0;
1004 uint32_t length
= 0, part_length
= 0;
1005 int32_t segmentlength
= 0;
1006 proto_item
*segment_item
= NULL
, *segmentlength_item
= NULL
, *number_of_parts_item
= NULL
, *segment_number_item
= NULL
, *segment_buffer_item
= NULL
;
1007 proto_tree
*segment_tree
= NULL
, *segment_buffer_tree
= NULL
;
1009 /* Add the Segment subtree */
1010 segment_item
= proto_tree_add_item(tree
, hf_saphdb_segment
, tvb
, offset
, 13, ENC_NA
);
1011 segment_tree
= proto_item_add_subtree(segment_item
, ett_saphdb
);
1012 proto_item_append_text(segment_item
, " (%d/%d)", nosegment
, number_of_segments
);
1014 /* Add the Segment fields */
1015 segmentlength
= tvb_get_int32(tvb
, offset
, ENC_LITTLE_ENDIAN
);
1016 segmentlength_item
= proto_tree_add_item(segment_tree
, hf_saphdb_segment_segmentlength
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
1019 proto_tree_add_item(segment_tree
, hf_saphdb_segment_segmentofs
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
1022 number_of_parts
= tvb_get_int16(tvb
, offset
, ENC_LITTLE_ENDIAN
);
1023 number_of_parts_item
= proto_tree_add_item(segment_tree
, hf_saphdb_segment_noofparts
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1026 segment_number
= tvb_get_int16(tvb
, offset
, ENC_LITTLE_ENDIAN
);
1027 segment_number_item
= proto_tree_add_item(segment_tree
, hf_saphdb_segment_segmentno
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1030 segmentkind
= tvb_get_int8(tvb
, offset
);
1031 proto_tree_add_item(segment_tree
, hf_saphdb_segment_segmentkind
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1035 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "Segment %s (", val_to_str_const(segmentkind
, saphdb_segment_segmentkind_vals
, "Unknown"));
1036 proto_item_append_text(segment_item
, ", %s", val_to_str_const(segmentkind
, saphdb_segment_segmentkind_vals
, "Unknown"));
1038 /* Check a couple of fields */
1039 if (segmentlength
< 13) {
1040 expert_add_info_format(pinfo
, segmentlength_item
, &ei_saphdb_segment_length
, "Segment length %d is invalid", segmentlength
);
1042 if (number_of_parts
< 0) {
1043 expert_add_info_format(pinfo
, number_of_parts_item
, &ei_saphdb_parts_number_incorrect
, "Number of parts %d is invalid", number_of_parts
);
1045 if (segment_number
< 0 || nosegment
!= segment_number
) {
1046 expert_add_info_format(pinfo
, segment_number_item
, &ei_saphdb_segments_incorrect_order
, "Segment number %d is invalid (expected %d)", segment_number
, nosegment
);
1049 /* Add additional fields according to the segment kind*/
1050 switch (segmentkind
) {
1051 case 1: /* Request */
1052 message_type
= tvb_get_int8(tvb
, offset
);
1053 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s)", val_to_str_const(message_type
, saphdb_segment_messagetype_vals
, "Unknown"));
1054 proto_item_append_text(segment_item
, ", %s", val_to_str_const(message_type
, saphdb_segment_messagetype_vals
, "Unknown"));
1055 proto_tree_add_item(segment_tree
, hf_saphdb_segment_messagetype
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1059 proto_tree_add_item(segment_tree
, hf_saphdb_segment_commit
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1062 proto_tree_add_item(segment_tree
, hf_saphdb_segment_commandoptions
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1066 proto_tree_add_item(segment_tree
, hf_saphdb_segment_reserved
, tvb
, offset
, 8, ENC_NA
);
1071 proto_tree_add_item(segment_tree
, hf_saphdb_segment_reserved
, tvb
, offset
, 1, ENC_NA
);
1075 function_code
= tvb_get_int16(tvb
, offset
, ENC_LITTLE_ENDIAN
);
1076 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s)", val_to_str_const(function_code
, saphdb_segment_functioncode_vals
, "Unknown"));
1077 proto_item_append_text(segment_item
, ", %s", val_to_str_const(function_code
, saphdb_segment_functioncode_vals
, "Unknown"));
1078 proto_tree_add_item(segment_tree
, hf_saphdb_segment_functioncode
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1082 proto_tree_add_item(segment_tree
, hf_saphdb_segment_reserved
, tvb
, offset
, 8, ENC_NA
);
1086 default: /* Error and other types */
1087 proto_tree_add_item(segment_tree
, hf_saphdb_segment_reserved
, tvb
, offset
, 11, ENC_NA
);
1090 col_append_str(pinfo
->cinfo
, COL_INFO
, ")");
1095 /* If the packet is compressed, compression will apply from here on. As we don't support compression yet, we stop dissecting here. */
1100 /* Add the Segment Buffer subtree */
1101 if (((uint32_t)segmentlength
> length
) && (number_of_parts
> 0)) {
1102 segment_buffer_item
= proto_tree_add_item(segment_tree
, hf_saphdb_segment_buffer
, tvb
, offset
, segmentlength
- length
, ENC_NA
);
1103 segment_buffer_tree
= proto_item_add_subtree(segment_buffer_item
, ett_saphdb
);
1105 /* Iterate over the parts and dissect them */
1106 for (uint16_t part_number
= 1; part_number
<= number_of_parts
&& tvb_reported_length_remaining(tvb
, offset
) >= 16; part_number
++) {
1107 part_length
= dissect_saphdb_part(tvb
, pinfo
, segment_buffer_tree
, NULL
, offset
, number_of_parts
, part_number
);
1108 offset
+= part_length
;
1109 length
+= part_length
;
1114 /* Adjust the item tree length */
1115 proto_item_set_len(segment_tree
, length
);
1122 dissect_saphdb_message(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1124 uint32_t offset
= 0;
1126 /* Add the protocol to the column */
1127 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "SAPHDB");
1128 /* Clear out stuff in the info column */
1129 col_clear(pinfo
->cinfo
,COL_INFO
);
1131 /* we are being asked for details */
1132 if (tvb_reported_length(tvb
) == 8 || tvb_reported_length(tvb
) == 14 || tvb_reported_length(tvb
) >= SAPHDB_HEADER_LEN
) {
1134 proto_item
*ti
= NULL
;
1135 proto_tree
*saphdb_tree
= NULL
;
1137 /* Add the main saphdb subtree */
1138 ti
= proto_tree_add_item(tree
, proto_saphdb
, tvb
, offset
, -1, ENC_NA
);
1139 saphdb_tree
= proto_item_add_subtree(ti
, ett_saphdb
);
1142 /* Initialization Request message */
1143 if (tvb_reported_length(tvb
) == 14) {
1144 proto_tree_add_item(saphdb_tree
, hf_saphdb_initialization_request
, tvb
, offset
, 14, ENC_NA
);
1146 col_set_str(pinfo
->cinfo
, COL_INFO
, "Initialization Request");
1148 /* Initialization Reply message */
1149 } else if (tvb_reported_length(tvb
) == 8) {
1150 proto_item
*initialization_reply
= NULL
;
1151 proto_tree
*initialization_reply_tree
= NULL
;
1153 /* Add the Initialization Reply subtree */
1154 initialization_reply
= proto_tree_add_item(saphdb_tree
, hf_saphdb_initialization_reply
, tvb
, offset
, 8, ENC_NA
);
1155 initialization_reply_tree
= proto_item_add_subtree(initialization_reply
, ett_saphdb
);
1157 proto_tree_add_item(initialization_reply_tree
, hf_saphdb_initialization_reply_product_version_major
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1159 proto_tree_add_item(initialization_reply_tree
, hf_saphdb_initialization_reply_product_version_minor
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1161 proto_tree_add_item(initialization_reply_tree
, hf_saphdb_initialization_reply_protocol_version_major
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1163 proto_tree_add_item(initialization_reply_tree
, hf_saphdb_initialization_reply_protocol_version_minor
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1166 col_set_str(pinfo
->cinfo
, COL_INFO
, "Initialization Reply");
1168 /* All other message types */
1169 } else if (tvb_reported_length(tvb
) >= SAPHDB_HEADER_LEN
) {
1171 bool compressed
= false;
1172 int16_t number_of_segments
= 0;
1173 uint32_t varpartlength
= 0;
1174 proto_item
*message_header_item
= NULL
, *varpartlength_item
= NULL
, *number_of_segments_item
= NULL
, *message_buffer_item
= NULL
, *compressed_buffer_item
= NULL
;
1175 proto_tree
*message_header_tree
= NULL
, *message_buffer_tree
= NULL
;
1177 /* Add the Message Header subtree */
1178 message_header_item
= proto_tree_add_item(saphdb_tree
, hf_saphdb_message_header
, tvb
, offset
, SAPHDB_HEADER_LEN
, ENC_NA
);
1179 message_header_tree
= proto_item_add_subtree(message_header_item
, ett_saphdb
);
1181 /* Add the Message Header fields */
1182 proto_tree_add_item(message_header_tree
, hf_saphdb_message_header_sessionid
, tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
1184 proto_tree_add_item(message_header_tree
, hf_saphdb_message_header_packetcount
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
1186 varpartlength_item
= proto_tree_add_item_ret_uint(message_header_tree
, hf_saphdb_message_header_varpartlength
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
, &varpartlength
);
1188 proto_tree_add_item(message_header_tree
, hf_saphdb_message_header_varpartsize
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
1190 number_of_segments
= tvb_get_int16(tvb
, offset
, ENC_LITTLE_ENDIAN
);
1191 number_of_segments_item
= proto_tree_add_item(message_header_tree
, hf_saphdb_message_header_noofsegm
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
1193 compressed
= tvb_get_int8(tvb
, offset
) == 2;
1194 proto_tree_add_item(message_header_tree
, hf_saphdb_message_header_packetoptions
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
1196 proto_tree_add_item(message_header_tree
, hf_saphdb_message_header_reserved
, tvb
, offset
, 1, ENC_NA
);
1198 proto_tree_add_item(message_header_tree
, hf_saphdb_message_header_compressionvarpartlength
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
1200 proto_tree_add_item(message_header_tree
, hf_saphdb_message_header_reserved
, tvb
, offset
, 4, ENC_NA
);
1203 /* Check the length of the variable part against the remaining packet */
1204 if ((uint32_t)tvb_reported_length_remaining(tvb
, offset
) != varpartlength
) {
1205 expert_add_info_format(pinfo
, varpartlength_item
, &ei_saphdb_varpartlenght_incorrect
, "Length of variable part %d is invalid", varpartlength
);
1206 varpartlength
= tvb_reported_length_remaining(tvb
, offset
);
1209 /* Add the Message Buffer subtree */
1210 if (varpartlength
> 0 && number_of_segments
> 0) {
1211 message_buffer_item
= proto_tree_add_item(saphdb_tree
, hf_saphdb_message_buffer
, tvb
, offset
, varpartlength
, ENC_NA
);
1212 message_buffer_tree
= proto_item_add_subtree(message_buffer_item
, ett_saphdb
);
1214 /* If the packet is compressed, the message header and the first segment header is sent uncompressed. We dissect the
1215 * first segment only and add a new item with the compressed buffer. Adding an expert warning as well. */
1217 offset
+= dissect_saphdb_segment(tvb
, pinfo
, message_buffer_tree
, NULL
, offset
, number_of_segments
, 1, compressed
);
1218 compressed_buffer_item
= proto_tree_add_item(message_buffer_tree
, hf_saphdb_compressed_buffer
, tvb
, offset
, varpartlength
, ENC_NA
);
1219 if (global_saphdb_highlight_items
){
1220 expert_add_info_format(pinfo
, compressed_buffer_item
, &ei_saphdb_compressed_unknown
, "Packet is compressed and decompression is not supported");
1224 /* Iterate over the segments and dissect them */
1225 for (uint16_t segment_number
= 1; segment_number
<= number_of_segments
&& tvb_reported_length_remaining(tvb
, offset
) >= 13; segment_number
++) {
1226 offset
+= dissect_saphdb_segment(tvb
, pinfo
, message_buffer_tree
, NULL
, offset
, number_of_segments
, segment_number
, compressed
);
1231 expert_add_info_format(pinfo
, number_of_segments_item
, &ei_saphdb_segments_number_incorrect
, "Number of segments %d is invalid", number_of_segments
);
1242 get_saphdb_pdu_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
, void *data _U_
)
1244 /* Entire HDB packets are of 32-bytes header plus the value in varpartlength field */
1245 uint32_t varpartlength
= tvb_get_uint32(tvb
, offset
+ 12, ENC_LITTLE_ENDIAN
);
1246 return varpartlength
+ SAPHDB_HEADER_LEN
;
1250 dissect_saphdb_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1252 return dissect_saphdb_message(tvb
, pinfo
, tree
, NULL
);
1256 dissect_saphdb(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
1258 if (tvb_reported_length(tvb
) == 14 || tvb_reported_length(tvb
) == 8) {
1259 return dissect_saphdb_tcp(tvb
, pinfo
, tree
, data
);
1263 /* Header must be present */
1264 if (!tvb_bytes_exist(tvb
, 0, SAPHDB_HEADER_LEN
))
1267 /* Filter on reserved bytes */
1268 if(tvb_get_uint8(tvb
, 23) || tvb_get_uint32(tvb
, 28, ENC_BIG_ENDIAN
))
1271 tcp_dissect_pdus(tvb
, pinfo
, tree
, true, SAPHDB_HEADER_LEN
, get_saphdb_pdu_len
, dissect_saphdb_tcp
, data
);
1273 return tvb_reported_length(tvb
);
1277 proto_register_saphdb(void)
1279 static hf_register_info hf
[] = {
1280 /* Initialization items */
1281 { &hf_saphdb_initialization_request
,
1282 { "Initialization Request", "saphdb.init_request", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1284 { &hf_saphdb_initialization_reply
,
1285 { "Initialization Reply", "saphdb.init_reply", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1286 { &hf_saphdb_initialization_reply_product_version_major
,
1287 { "Product Version Major", "saphdb.init_reply.product_version.major", FT_INT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1288 { &hf_saphdb_initialization_reply_product_version_minor
,
1289 { "Product Version Minor", "saphdb.init_reply.product_version.minor", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1290 { &hf_saphdb_initialization_reply_protocol_version_major
,
1291 { "Protocol Version Major", "saphdb.init_reply.protocol_version.major", FT_INT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1292 { &hf_saphdb_initialization_reply_protocol_version_minor
,
1293 { "Protocol Version Minor", "saphdb.init_reply.protocol_version.minor", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1295 /* Message Header items */
1296 { &hf_saphdb_message_header
,
1297 { "Message Header", "saphdb.message_header", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1298 { &hf_saphdb_message_header_sessionid
,
1299 { "Session ID", "saphdb.sessionid", FT_INT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1300 { &hf_saphdb_message_header_packetcount
,
1301 { "Packet Count", "saphdb.packetcount", FT_INT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1302 { &hf_saphdb_message_header_varpartlength
,
1303 { "Var Part Length", "saphdb.varpartlength", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1304 { &hf_saphdb_message_header_varpartsize
,
1305 { "Var Part Size", "saphdb.varpartsize", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1306 { &hf_saphdb_message_header_noofsegm
,
1307 { "Number of Segments", "saphdb.noofsegm", FT_INT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1308 { &hf_saphdb_message_header_packetoptions
,
1309 { "Packet Options", "saphdb.packetoptions", FT_INT8
, BASE_DEC
, VALS(saphdb_message_header_packetoptions_vals
), 0x0, NULL
, HFILL
}},
1310 { &hf_saphdb_message_header_compressionvarpartlength
,
1311 { "Compression Var Part Length", "saphdb.compressionvarpartlength", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1312 { &hf_saphdb_message_header_reserved
,
1313 { "Reserved", "saphdb.reserved", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1314 /* Message Buffer items */
1315 { &hf_saphdb_message_buffer
,
1316 { "Message Buffer", "saphdb.messagebuffer", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1317 { &hf_saphdb_compressed_buffer
,
1318 { "Compressed Buffer", "saphdb.compressedbuffer", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1321 { &hf_saphdb_segment
,
1322 { "Segment", "saphdb.segment", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1323 { &hf_saphdb_segment_segmentlength
,
1324 { "Segment Length", "saphdb.segment.length", FT_INT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1325 { &hf_saphdb_segment_segmentofs
,
1326 { "Segment Offset", "saphdb.segment.offset", FT_INT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1327 { &hf_saphdb_segment_noofparts
,
1328 { "Number of Parts", "saphdb.segment.noofparts", FT_INT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1329 { &hf_saphdb_segment_segmentno
,
1330 { "Segment Number", "saphdb.segment.segmentno", FT_INT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1331 { &hf_saphdb_segment_segmentkind
,
1332 { "Segment Kind", "saphdb.segment.kind", FT_INT8
, BASE_DEC
, VALS(saphdb_segment_segmentkind_vals
), 0x0, NULL
, HFILL
}},
1333 { &hf_saphdb_segment_messagetype
,
1334 { "Message Type", "saphdb.segment.messagetype", FT_INT8
, BASE_DEC
, VALS(saphdb_segment_messagetype_vals
), 0x0, NULL
, HFILL
}},
1335 { &hf_saphdb_segment_commit
,
1336 { "Commit", "saphdb.segment.commit", FT_INT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1337 { &hf_saphdb_segment_commandoptions
,
1338 { "Command Options", "saphdb.segment.commandoptions", FT_INT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1339 { &hf_saphdb_segment_functioncode
,
1340 { "Function Code", "saphdb.segment.functioncode", FT_INT16
, BASE_DEC
, VALS(saphdb_segment_functioncode_vals
), 0x0, NULL
, HFILL
}},
1341 { &hf_saphdb_segment_reserved
,
1342 { "Reserved", "saphdb.segment.reserved", FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1344 /* Segment Buffer items */
1345 { &hf_saphdb_segment_buffer
,
1346 { "Segment Buffer", "saphdb.segment.buffer", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1350 { "Part", "saphdb.segment.part", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1351 { &hf_saphdb_part_partkind
,
1352 { "Part Kind", "saphdb.segment.part.partkind", FT_INT8
, BASE_DEC
, VALS(saphdb_part_partkind_vals
), 0x0, NULL
, HFILL
}},
1353 { &hf_saphdb_part_partattributes
,
1354 { "Part Attributes", "saphdb.segment.part.partattributes", FT_INT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1355 { &hf_saphdb_part_argumentcount
,
1356 { "Argument Count", "saphdb.segment.part.argumentcount", FT_INT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1357 { &hf_saphdb_part_bigargumentcount
,
1358 { "Big Argument Count", "saphdb.segment.part.bigargumentcount", FT_INT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1359 { &hf_saphdb_part_bufferlength
,
1360 { "Buffer Length", "saphdb.segment.part.bufferlength", FT_INT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1361 { &hf_saphdb_part_buffersize
,
1362 { "Buffer Size", "saphdb.segment.part.buffersize", FT_INT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1364 /* Part Buffer items */
1365 { &hf_saphdb_part_buffer
,
1366 { "Part Buffer", "saphdb.segment.part.buffer", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1368 /* Part Buffer Option Part Data items */
1369 { &hf_saphdb_part_option_argcount
,
1370 { "Argument Row Count", "saphdb.segment.part.option.argcount", FT_INT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1371 { &hf_saphdb_part_option_name
,
1372 { "Option Name", "saphdb.segment.part.option.name", FT_INT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1373 { &hf_saphdb_part_option_type
,
1374 { "Option Type", "saphdb.segment.part.option.type", FT_INT8
, BASE_DEC
, VALS(saphdb_part_type_vals
), 0x0, NULL
, HFILL
}},
1375 { &hf_saphdb_part_option_length
,
1376 { "Option Length", "saphdb.segment.part.option.length", FT_INT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1377 { &hf_saphdb_part_option_value
,
1378 { "Option Value", "saphdb.segment.part.option.value", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1379 { &hf_saphdb_part_option_value_bool
,
1380 { "Option Value", "saphdb.segment.part.option.value.bool", FT_BOOLEAN
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1381 { &hf_saphdb_part_option_value_byte
,
1382 { "Option Value", "saphdb.segment.part.option.value.byte", FT_INT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1383 { &hf_saphdb_part_option_value_short
,
1384 { "Option Value", "saphdb.segment.part.option.value.short", FT_INT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1385 { &hf_saphdb_part_option_value_int
,
1386 { "Option Value", "saphdb.segment.part.option.value.int", FT_INT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1387 { &hf_saphdb_part_option_value_bigint
,
1388 { "Option Value", "saphdb.segment.part.option.value.bigint", FT_INT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1389 { &hf_saphdb_part_option_value_string
,
1390 { "Option Value", "saphdb.segment.part.option.value.string", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1391 { &hf_saphdb_part_option_value_double
,
1392 { "Option Value", "saphdb.segment.part.option.value.double", FT_DOUBLE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1394 /* SAP HDB Part Buffer COMMAND items */
1395 { &hf_saphdb_part_command
,
1396 { "Command", "saphdb.segment.part.command", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1398 /* SAP HDB Part Buffer ERROR items */
1399 { &hf_saphdb_part_error_code
,
1400 { "Error Code", "saphdb.segment.part.error.code", FT_INT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1401 { &hf_saphdb_part_error_position
,
1402 { "Error Position", "saphdb.segment.part.error.position", FT_INT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1403 { &hf_saphdb_part_error_text_length
,
1404 { "Error Text Length", "saphdb.segment.part.error.text_length", FT_INT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1405 { &hf_saphdb_part_error_level
,
1406 { "Error Level", "saphdb.segment.part.error.level", FT_INT8
, BASE_DEC
, VALS(saphdb_error_level_vals
), 0x0, NULL
, HFILL
}},
1407 { &hf_saphdb_part_error_sqlstate
,
1408 { "SQL State", "saphdb.segment.part.error.sqlstate", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1409 { &hf_saphdb_part_error_text
,
1410 { "Error Text", "saphdb.segment.part.error.text", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1412 /* Part Buffer AUTHENTICATION items */
1413 { &hf_saphdb_part_authentication_field_count
,
1414 { "Field Count", "saphdb.segment.part.authentication.fieldcount", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1415 { &hf_saphdb_part_authentication_field_length
,
1416 { "Field Length", "saphdb.segment.part.authentication.fieldlength", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
}},
1417 { &hf_saphdb_part_authentication_field_value
,
1418 { "Field Value", "saphdb.segment.part.authentication.fieldvalue", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1420 /* SAP HDB Part Buffer CLIENTID items */
1421 { &hf_saphdb_part_clientid
,
1422 { "Client ID", "saphdb.segment.part.clientid", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
}},
1426 /* Setup protocol subtree array */
1427 static int *ett
[] = {
1431 /* Register the expert info */
1432 static ei_register_info ei
[] = {
1433 { &ei_saphdb_compressed_unknown
, { "saphdb.compressed", PI_UNDECODED
, PI_WARN
, "The packet is compressed, and decompression is not supported", EXPFILL
}},
1434 { &ei_saphdb_option_part_unknown
, { "saphdb.segment.part.option.unknown", PI_UNDECODED
, PI_WARN
, "The Option Part has a unknown type that is not dissected", EXPFILL
}},
1435 { &ei_saphdb_segments_incorrect_order
, { "saphdb.segment.segmentno.invalid", PI_MALFORMED
, PI_ERROR
, "The segments are in incorrect order or are invalid", EXPFILL
}},
1436 { &ei_saphdb_segments_number_incorrect
, { "saphdb.noofsegm.invalid", PI_MALFORMED
, PI_ERROR
, "The number of segments is incorrect", EXPFILL
}},
1437 { &ei_saphdb_segment_length
, { "saphdb.segment.segmentlength.invalid", PI_MALFORMED
, PI_ERROR
, "The segment length is incorrect", EXPFILL
}},
1438 { &ei_saphdb_buffer_length
, { "saphdb.segment.part.bufferlength.invalid", PI_MALFORMED
, PI_ERROR
, "The part buffer length is incorrect", EXPFILL
}},
1439 { &ei_saphdb_parts_number_incorrect
, { "saphdb.segment.noofparts.invalid", PI_MALFORMED
, PI_ERROR
, "The number of parts is incorrect", EXPFILL
}},
1440 { &ei_saphdb_varpartlenght_incorrect
, { "saphdb.varpartlength.invalid", PI_MALFORMED
, PI_ERROR
, "The length is incorrect", EXPFILL
}},
1443 module_t
*saphdb_module
;
1444 expert_module_t
* saphdb_expert
;
1446 /* Register the protocol */
1447 proto_saphdb
= proto_register_protocol("SAP HANA SQL Command Network Protocol", "SAPHDB", "saphdb");
1449 saphdb_expert
= expert_register_protocol(proto_saphdb
);
1450 expert_register_field_array(saphdb_expert
, ei
, array_length(ei
));
1452 saphdb_handle
= register_dissector("saphdb", dissect_saphdb
, proto_saphdb
);
1454 proto_register_field_array(proto_saphdb
, hf
, array_length(hf
));
1455 proto_register_subtree_array(ett
, array_length(ett
));
1457 /* Register the preferences */
1458 saphdb_module
= prefs_register_protocol(proto_saphdb
, proto_reg_handoff_saphdb
);
1460 range_convert_str(wmem_epan_scope(), &global_saphdb_port_range
, SAPHDB_PORT_RANGE
, MAX_TCP_PORT
);
1461 prefs_register_range_preference(saphdb_module
, "tcp_ports", "SAP HANA SQL Command Network Protocol port numbers", "Port numbers used for SAP HANA SQL Command Network Protocol (default " SAPHDB_PORT_RANGE
")", &global_saphdb_port_range
, MAX_TCP_PORT
);
1463 prefs_register_bool_preference(saphdb_module
, "highlight_unknown_items", "Highlight unknown SAP HANA HDB items", "Whether the SAP HANA HDB Protocol dissector should highlight unknown items (might be noise and generate a lot of expert warnings)", &global_saphdb_highlight_items
);
1468 * Helpers for dealing with the port range
1470 static void range_delete_callback (uint32_t port
, void *ptr _U_
)
1472 dissector_delete_uint("tcp.port", port
, saphdb_handle
);
1474 static void range_add_callback (uint32_t port
, void *ptr _U_
)
1476 dissector_add_uint("tcp.port", port
, saphdb_handle
);
1480 * Register Hand off for the SAP HDB Protocol
1483 proto_reg_handoff_saphdb(void)
1485 static bool initialized
= false;
1486 static range_t
*saphdb_port_range
;
1489 saphdb_handle
= create_dissector_handle(dissect_saphdb
, proto_saphdb
);
1490 saphdb_handle_tls
= register_dissector_with_description("saphdb_tls", "SAPHDB over TLS", dissect_saphdb
, proto_saphdb
);
1493 range_foreach(saphdb_port_range
, range_delete_callback
, NULL
);
1494 wmem_free(wmem_epan_scope(), saphdb_port_range
);
1497 saphdb_port_range
= range_copy(wmem_epan_scope(), global_saphdb_port_range
);
1498 range_foreach(saphdb_port_range
, range_add_callback
, NULL
);
1499 ssl_dissector_add(0, saphdb_handle_tls
);
1501 gssapi_handle
= find_dissector_add_dependency("gssapi", proto_saphdb
);
1506 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1511 * indent-tabs-mode: t
1514 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1515 * :indentSize=8:tabSize=8:noTabs=false: