1 /* packet-elasticsearch.c
3 * Routines for dissecting Elasticsearch
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include <epan/packet.h>
14 #include <epan/expert.h>
16 #include "packet-tcp.h"
18 #define ELASTICSEARCH_DISCOVERY_PORT 54328 /* Not IANA registered */
19 #define ELASTICSEARCH_BINARY_PORT 9300 /* Not IANA registered */
21 #define ELASTICSEARCH_HEADER_SIZE_VERSION 7060099 /* First version to support variable header size */
22 #define ELASTICSEARCH_THREAD_CONTEXT_VERSION 5000099 /* First version to include the thread context */
23 #define ELASTICSEARCH_FEATURES_VERSION 6030099 /* First version which includes a feature list */
25 #define IPv4_ADDRESS_LENGTH 4
26 #define ELASTICSEARCH_STATUS_FLAG_RESPONSE 1 /* 001 */
27 #define ELASTICSEARCH_STATUS_FLAG_ERROR 2 /* 010 */
28 #define ELASTICSEARCH_STATUS_FLAG_COMPRESSED 4 /* 100 */
30 #define ELASTICSEARCH_VERSION_LABEL_LENGTH 19 /* This many characters: XX.XX.XX (XXXXXXXX) */
31 #define ELASTICSEARCH_HEADER_LENGTH 6 /* Bytes 3-6 are the length, 1-2 is the magic number */
33 #define ELASTICSEARCH_MESSAGE_LENGTH_OFFSET 2
34 #define ELASTICSEARCH_BINARY_HEADER_TOKEN 0x4553
35 #define BITS_IN_A_BYTE 8
53 void proto_register_elasticsearch(void);
54 void proto_reg_handoff_elasticsearch(void);
56 static dissector_handle_t elasticsearch_handle_binary
;
57 static dissector_handle_t elasticsearch_zen_handle
;
59 static int proto_elasticsearch
;
62 static int hf_elasticsearch_internal_header
;
63 static int hf_elasticsearch_version
;
64 static int hf_elasticsearch_ping_request_id
;
65 static int hf_elasticsearch_cluster_name
;
66 static int hf_elasticsearch_node_name
;
67 static int hf_elasticsearch_node_id
;
68 static int hf_elasticsearch_host_name
;
69 static int hf_elasticsearch_host_address
;
70 static int hf_elasticsearch_address_type
;
71 static int hf_elasticsearch_address_format
;
72 static int hf_elasticsearch_address_name
;
73 static int hf_elasticsearch_address_length
;
74 static int hf_elasticsearch_address_ipv4
;
75 static int hf_elasticsearch_address_ipv6
;
76 static int hf_elasticsearch_address_ipv6_scope_id
;
77 static int hf_elasticsearch_attributes_length
;
78 static int hf_elasticsearch_address_port
;
79 static int hf_elasticsearch_header_token
;
80 static int hf_elasticsearch_header_message_length
;
81 static int hf_elasticsearch_header_request_id
;
82 static int hf_elasticsearch_header_status_flags
;
83 static int hf_elasticsearch_header_status_flags_message_type
;
84 static int hf_elasticsearch_header_status_flags_error
;
85 static int hf_elasticsearch_header_status_flags_compression
;
86 static int hf_elasticsearch_header_size
;
87 static int hf_elasticsearch_header_request
;
88 static int hf_elasticsearch_header_response
;
89 static int hf_elasticsearch_header_key
;
90 static int hf_elasticsearch_header_value
;
92 static int hf_elasticsearch_feature
;
93 static int hf_elasticsearch_action
;
94 static int hf_elasticsearch_data
;
95 static int hf_elasticsearch_data_compressed
;
98 static expert_field ei_elasticsearch_unsupported_version
;
99 static expert_field ei_elasticsearch_unsupported_address_format
;
100 static expert_field ei_elasticsearch_unsupported_address_type
;
104 static int ett_elasticsearch
;
105 static int ett_elasticsearch_address
;
106 static int ett_elasticsearch_discovery_node
;
107 static int ett_elasticsearch_status_flags
;
108 static int ett_elasticsearch_header
;
110 /* Forward declarations */
111 static int dissect_elasticsearch_zen_ping(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
);
113 static const value_string address_types
[] = {
115 { 0x1, "Inet Socket" },
116 #define ADDRESS_TYPE_SOCKET 0x1
121 static const value_string address_format
[] = {
122 #define ADDRESS_FORMAT_NUEMRIC 0x0
124 #define ADDRESS_FORMAT_STRING 0x1
129 static const value_string status_flag_message_type
[] = {
135 static void elasticsearch_format_version(char *buf
, uint32_t value
) {
136 snprintf(buf
, ELASTICSEARCH_VERSION_LABEL_LENGTH
, "%d.%d.%d (%d)", (value
/ 1000000) % 100,
137 (value
/ 10000) % 100, (value
/ 100) % 100, value
);
140 static vint_t
read_vint(tvbuff_t
*tvb
, int offset
){
141 /* See: org.elasticsearch.common.io.stream.StreamInput#readVInt */
143 uint8_t b
= tvb_get_uint8(tvb
, offset
);
144 vint
.value
= b
& 0x7F;
145 if ((b
& 0x80) == 0) {
149 b
= tvb_get_uint8(tvb
, offset
+1);
150 vint
.value
|= (b
& 0x7F) << 7;
151 if ((b
& 0x80) == 0) {
155 b
= tvb_get_uint8(tvb
, offset
+2);
156 vint
.value
|= (b
& 0x7F) << 14;
157 if ((b
& 0x80) == 0) {
161 b
= tvb_get_uint8(tvb
, offset
+3);
162 vint
.value
|= (b
& 0x7F) << 21;
163 if ((b
& 0x80) == 0) {
167 b
= tvb_get_uint8(tvb
, offset
+4);
169 vint
.value
|= ((b
& 0x7F) << 28);
173 static vstring_t
read_vstring(wmem_allocator_t
*scope
, tvbuff_t
*tvb
, int offset
) {
175 int string_starting_offset
;
178 vstring
.vint_length
= read_vint(tvb
, offset
);
179 string_starting_offset
= offset
+ vstring
.vint_length
.length
;
180 string_length
= vstring
.vint_length
.value
;
182 vstring
.value
= tvb_get_string_enc(scope
, tvb
, string_starting_offset
, string_length
, ENC_UTF_8
);
183 vstring
.length
= string_length
+ vstring
.vint_length
.length
;
188 static int elasticsearch_partial_dissect_address(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
) {
189 proto_tree
*address_tree
;
190 proto_item
*address_item
;
192 uint8_t es_address_format
;
193 uint8_t address_length
;
194 vstring_t address_name
;
195 uint16_t address_type_id
;
197 /* Store this away for later */
198 start_offset
= offset
;
201 address_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, -1, ett_elasticsearch_address
, &address_item
, "Address" );
204 proto_tree_add_item(address_tree
, hf_elasticsearch_address_type
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
205 address_type_id
= tvb_get_ntohs(tvb
, offset
);
207 /* Only socket address types are supported (and only make sense to be supported) */
208 if(address_type_id
!= ADDRESS_TYPE_SOCKET
) {
209 expert_add_info(pinfo
, tree
, &ei_elasticsearch_unsupported_address_type
);
214 es_address_format
= tvb_get_uint8(tvb
, offset
);
215 proto_tree_add_item(address_tree
, hf_elasticsearch_address_format
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
218 switch(es_address_format
) {
219 case ADDRESS_FORMAT_NUEMRIC
:
220 address_length
= tvb_get_uint8(tvb
, offset
);
221 proto_tree_add_item(address_tree
, hf_elasticsearch_address_length
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
223 /* Its either IPv4 or IPv6 depending on the length */
224 if (address_length
== IPv4_ADDRESS_LENGTH
) {
225 proto_tree_add_item(address_tree
, hf_elasticsearch_address_ipv4
, tvb
, offset
, 4, ENC_NA
);
229 proto_tree_add_item(address_tree
, hf_elasticsearch_address_ipv6
, tvb
, offset
, 16, ENC_NA
);
231 proto_tree_add_item(address_tree
, hf_elasticsearch_address_ipv6_scope_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
236 case ADDRESS_FORMAT_STRING
:
237 address_name
= read_vstring(pinfo
->pool
, tvb
, offset
);
238 proto_tree_add_string(address_tree
, hf_elasticsearch_address_name
, tvb
, offset
, address_name
.length
, address_name
.value
);
239 offset
+= address_name
.length
;
243 /* Shouldn't get here, invalid format type */
244 expert_add_info(pinfo
, tree
, &ei_elasticsearch_unsupported_address_format
);
248 proto_tree_add_item(address_item
, hf_elasticsearch_address_port
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
251 /* Fix up the length of the subtree */
252 proto_item_set_len(address_item
, offset
- start_offset
);
257 static version_t
elasticsearch_parse_version(tvbuff_t
*tvb
, int offset
){
259 vint_t raw_version_value
;
261 raw_version_value
= read_vint(tvb
, offset
);
262 version
.length
= raw_version_value
.length
;
263 version
.value
= raw_version_value
.value
;
264 snprintf(version
.string
, sizeof(version
.string
), "%d.%d.%d", (version
.value
/ 1000000) % 100,
265 (version
.value
/ 10000) % 100, (version
.value
/ 100) % 100);
270 static int dissect_elasticsearch_zen_ping(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
){
273 vstring_t cluster_name
;
277 vstring_t host_address
;
278 vint_t attributes_length
;
279 version_t node_version
;
280 proto_item
*root_elasticsearch_item
;
281 proto_tree
*elasticsearch_tree
;
282 proto_tree
*discovery_node_tree
;
283 proto_item
*discovery_node_item
;
286 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Elasticsearch");
287 col_clear(pinfo
->cinfo
, COL_INFO
);
289 root_elasticsearch_item
= proto_tree_add_item(tree
, proto_elasticsearch
, tvb
, 0, -1, ENC_NA
);
290 elasticsearch_tree
= proto_item_add_subtree(root_elasticsearch_item
,ett_elasticsearch
);
292 /* Let the user know its a discovery packet */
293 col_set_str(pinfo
->cinfo
, COL_INFO
, "Zen Ping: ");
296 /* Add the internal header */
297 proto_tree_add_item(elasticsearch_tree
, hf_elasticsearch_internal_header
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
300 /* Add the variable length encoded version string */
301 version
= elasticsearch_parse_version(tvb
, offset
);
302 proto_tree_add_uint(elasticsearch_tree
, hf_elasticsearch_version
, tvb
, offset
, version
.length
, version
.value
);
303 offset
+= version
.length
;
305 /* Ping request ID */
306 proto_tree_add_item(elasticsearch_tree
, hf_elasticsearch_ping_request_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
310 cluster_name
= read_vstring(pinfo
->pool
, tvb
, offset
);
311 proto_tree_add_string(elasticsearch_tree
, hf_elasticsearch_cluster_name
, tvb
, offset
, cluster_name
.length
, cluster_name
.value
);
312 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "cluster=%s", cluster_name
.value
);
313 offset
+= cluster_name
.length
;
316 /* Discovery node tree */
317 discovery_node_tree
= proto_tree_add_subtree(elasticsearch_tree
, tvb
, offset
, -1, ett_elasticsearch_discovery_node
, &discovery_node_item
, "Node" );
320 node_name
= read_vstring(pinfo
->pool
, tvb
, offset
);
321 proto_tree_add_string(discovery_node_tree
, hf_elasticsearch_node_name
, tvb
, offset
, node_name
.length
, node_name
.value
);
322 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", name=%s", node_name
.value
);
323 offset
+= node_name
.length
;
325 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", version=%s", version
.string
);
329 node_id
= read_vstring(pinfo
->pool
, tvb
, offset
);
330 proto_tree_add_string(discovery_node_tree
, hf_elasticsearch_node_id
, tvb
, offset
, node_id
.length
, node_id
.value
);
331 offset
+= node_id
.length
;
334 host_name
= read_vstring(pinfo
->pool
, tvb
, offset
);
335 proto_tree_add_string(discovery_node_tree
, hf_elasticsearch_host_name
, tvb
, offset
, host_name
.length
, host_name
.value
);
336 offset
+= host_name
.length
;
339 host_address
= read_vstring(pinfo
->pool
, tvb
, offset
);
340 proto_tree_add_string(discovery_node_tree
, hf_elasticsearch_host_address
, tvb
, offset
, host_address
.length
, host_address
.value
);
341 offset
+= host_address
.length
;
344 offset
= elasticsearch_partial_dissect_address(tvb
, pinfo
, discovery_node_tree
, offset
);
346 /* Attributes. These are zero for discovery packets */
347 attributes_length
= read_vint(tvb
, offset
);
348 proto_tree_add_uint(discovery_node_tree
, hf_elasticsearch_attributes_length
, tvb
, offset
, attributes_length
.length
, attributes_length
.value
);
349 offset
+= attributes_length
.length
;
352 node_version
= elasticsearch_parse_version(tvb
, offset
);
353 proto_tree_add_uint(elasticsearch_tree
, hf_elasticsearch_version
, tvb
, offset
, node_version
.length
, node_version
.value
);
354 offset
+= node_version
.length
;
359 static int elasticsearch_binary_header_is_valid(tvbuff_t
*tvb
){
360 /* Header was introduced in V0.20.0RC1. At the moment I'm not supporting versions before this
361 * See: org.elasticsearch.transport.netty.NettyHeader#writeHeader
363 return tvb_captured_length(tvb
) >= 2 && tvb_get_ntohs(tvb
, 0) == ELASTICSEARCH_BINARY_HEADER_TOKEN
;
366 static int elasticsearch_transport_status_flag_is_a_response(int8_t transport_status_flags
) {
367 return transport_status_flags
& ELASTICSEARCH_STATUS_FLAG_RESPONSE
;
370 static int transport_status_flag_is_a_request(int8_t transport_status_flags
){
371 return !elasticsearch_transport_status_flag_is_a_response(transport_status_flags
);
374 static int elasticsearch_is_compressed(int8_t transport_status_flags
){
376 return transport_status_flags
& ELASTICSEARCH_STATUS_FLAG_COMPRESSED
;
379 static void elasticsearch_decode_binary_request(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
, int8_t transport_status_flags
, uint32_t version
) {
383 vstring_t action
, feature
;
385 if(elasticsearch_is_compressed(transport_status_flags
)){
386 proto_tree_add_item(tree
, hf_elasticsearch_data_compressed
, tvb
, offset
, -1, ENC_NA
);
387 col_append_str(pinfo
->cinfo
, COL_INFO
, "[COMPRESSED], ");
389 if (version
>= ELASTICSEARCH_FEATURES_VERSION
) {
390 features
= read_vint(tvb
, offset
);
391 offset
+= features
.length
;
392 for (i
= 0; i
< features
.value
; i
++) {
393 feature
= read_vstring(pinfo
->pool
, tvb
, offset
);
394 proto_tree_add_string(tree
, hf_elasticsearch_feature
, tvb
, offset
, feature
.length
, feature
.value
);
395 offset
+= feature
.length
;
399 action
= read_vstring(pinfo
->pool
, tvb
, offset
);
400 proto_tree_add_string(tree
, hf_elasticsearch_action
, tvb
, offset
, action
.length
, action
.value
);
401 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "action=%s, ", action
.value
);
402 offset
+= action
.length
;
403 proto_tree_add_item(tree
, hf_elasticsearch_data
, tvb
, offset
, -1, ENC_NA
);
407 static void append_status_info_to_column(packet_info
*pinfo
, int8_t transport_status_flags
) {
408 if(transport_status_flags
& ELASTICSEARCH_STATUS_FLAG_ERROR
){
409 col_append_str(pinfo
->cinfo
, COL_INFO
, "[ERROR], ");
411 col_append_str(pinfo
->cinfo
, COL_INFO
, "[OK], ");
415 static void elasticsearch_decode_binary_response(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
, int8_t transport_status_flags
, uint32_t version _U_
) {
416 append_status_info_to_column(pinfo
, transport_status_flags
);
417 if(elasticsearch_is_compressed(transport_status_flags
)){
418 col_append_str(pinfo
->cinfo
, COL_INFO
, "[COMPRESSED], ");
419 proto_tree_add_item(tree
, hf_elasticsearch_data_compressed
, tvb
, offset
, -1, ENC_NA
);
421 proto_tree_add_item(tree
, hf_elasticsearch_data
, tvb
, offset
, tvb_reported_length_remaining(tvb
, offset
), ENC_NA
);
426 static int elasticsearch_dissect_valid_binary_packet(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
){
430 int8_t transport_status_flags
;
433 vint_t request_headers
, response_headers
;
434 vstring_t header_key
;
435 vint_t header_values
;
436 vstring_t header_value
;
437 proto_item
*header_item
;
438 proto_tree
*header_tree
;
439 proto_item
*transport_status_flags_item
;
440 proto_tree
*transport_status_flags_tree
;
443 * Request: org.elasticsearch.transport.netty.NettyTransport#sendRequest
444 * Response: org.elasticsearch.transport.netty.NettyTransportChannel#sendResponse
447 /* org.elasticsearch.transport.netty.NettyHeader#writeHeader
449 * Token/Magic number that is at the start of all ES packets
451 proto_tree_add_item(tree
, hf_elasticsearch_header_token
, tvb
, offset
, 2, ENC_ASCII
);
455 proto_tree_add_item(tree
, hf_elasticsearch_header_message_length
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
459 proto_tree_add_item(tree
, hf_elasticsearch_header_request_id
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
460 request_id
= tvb_get_ntoh64(tvb
, offset
);
463 /* Transport status: org.elasticsearch.transport.support.TransportStatus */
464 transport_status_flags
= tvb_get_uint8(tvb
, offset
);
465 transport_status_flags_item
= proto_tree_add_uint(tree
, hf_elasticsearch_header_status_flags
, tvb
, offset
, 1, transport_status_flags
);
466 transport_status_flags_tree
= proto_item_add_subtree(transport_status_flags_item
, ett_elasticsearch_status_flags
);
467 if(elasticsearch_transport_status_flag_is_a_response(transport_status_flags
)){
468 col_append_str(pinfo
->cinfo
, COL_INFO
, "Response: ");
470 col_append_str(pinfo
->cinfo
, COL_INFO
, "Request: ");
472 proto_tree_add_bits_item(transport_status_flags_tree
, hf_elasticsearch_header_status_flags_compression
, tvb
, offset
* BITS_IN_A_BYTE
+ 5, 1, ENC_BIG_ENDIAN
);
473 proto_tree_add_bits_item(transport_status_flags_tree
, hf_elasticsearch_header_status_flags_error
, tvb
, offset
* BITS_IN_A_BYTE
+ 6, 1, ENC_BIG_ENDIAN
);
474 proto_tree_add_bits_item(transport_status_flags_tree
, hf_elasticsearch_header_status_flags_message_type
, tvb
, offset
* BITS_IN_A_BYTE
+ 7, 1, ENC_BIG_ENDIAN
);
478 proto_tree_add_item_ret_uint(tree
, hf_elasticsearch_version
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &version
);
481 /* Variable header size */
482 if (version
>= ELASTICSEARCH_HEADER_SIZE_VERSION
) {
483 proto_tree_add_item(tree
, hf_elasticsearch_header_size
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
487 if (version
>= ELASTICSEARCH_THREAD_CONTEXT_VERSION
) {
488 /* Request headers */
489 request_headers
= read_vint(tvb
, offset
);
490 offset
+= request_headers
.length
;
491 for (i
= 0; i
< request_headers
.value
; i
++) {
492 header_key
= read_vstring(pinfo
->pool
, tvb
, offset
);
493 header_value
= read_vstring(pinfo
->pool
, tvb
, offset
+ header_key
.length
);
495 header_item
= proto_tree_add_item(tree
, hf_elasticsearch_header_request
, tvb
, offset
, header_key
.length
+ header_value
.length
, ENC_NA
);
496 header_tree
= proto_item_add_subtree(header_item
, ett_elasticsearch_header
);
498 proto_tree_add_string(header_tree
, hf_elasticsearch_header_key
, tvb
, offset
, header_key
.length
, header_key
.value
);
499 proto_tree_add_string(header_tree
, hf_elasticsearch_header_value
, tvb
, offset
+ header_key
.length
, header_value
.length
, header_value
.value
);
501 proto_item_append_text(header_item
, ": %s: %s", header_key
.value
, header_value
.value
);
503 offset
+= header_key
.length
;
504 offset
+= header_value
.length
;
507 /* Response headers */
508 response_headers
= read_vint(tvb
, offset
);
509 offset
+= response_headers
.length
;
510 for (i
= 0; i
< response_headers
.value
; i
++) {
511 header_item
= proto_tree_add_item(tree
, hf_elasticsearch_header_response
, tvb
, offset
, 0, ENC_NA
);
512 header_tree
= proto_item_add_subtree(header_item
, ett_elasticsearch_header
);
514 header_key
= read_vstring(pinfo
->pool
, tvb
, offset
);
515 proto_tree_add_string(header_tree
, hf_elasticsearch_header_key
, tvb
, offset
, header_key
.length
, header_key
.value
);
516 proto_item_append_text(header_item
, ": %s", header_key
.value
);
517 offset
+= header_key
.length
;
519 header_values
= read_vint(tvb
, offset
);
520 offset
+= header_values
.length
;
522 for (j
= 0; j
< header_values
.value
; j
++) {
523 header_value
= read_vstring(pinfo
->pool
, tvb
, offset
);
524 proto_tree_add_string(header_tree
, hf_elasticsearch_header_value
, tvb
, offset
, header_value
.length
, header_value
.value
);
525 proto_item_append_text(header_item
, j
> 0 ? ", %s" : "%s", header_value
.value
);
526 offset
+= header_value
.length
;
529 proto_item_set_end(header_item
, tvb
, offset
);
533 /* Only requests have features and actions */
534 if (transport_status_flag_is_a_request(transport_status_flags
)) {
535 elasticsearch_decode_binary_request(tvb
, pinfo
, tree
, offset
, transport_status_flags
, version
);
537 elasticsearch_decode_binary_response(tvb
, pinfo
, tree
, offset
, transport_status_flags
, version
);
539 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "request_id=%"PRIu64
" ", request_id
);
542 /* Everything is marked as data, return the whole tvb as the length */
543 return tvb_captured_length(tvb
);
546 static unsigned elasticsearch_get_binary_message_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
,
547 int offset
, void *data _U_
)
549 /* length is two bytes into the packet, also the length doesn't include the starting 6 bytes */
550 return (unsigned)tvb_get_ntohl(tvb
, offset
+ELASTICSEARCH_MESSAGE_LENGTH_OFFSET
) + ELASTICSEARCH_HEADER_LENGTH
;
553 static int dissect_elasticsearch_binary(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
) {
556 proto_item
*root_elasticsearch_item
;
557 proto_tree
*elasticsearch_tree
;
559 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Elasticsearch");
560 col_clear(pinfo
->cinfo
, COL_INFO
);
562 root_elasticsearch_item
= proto_tree_add_item(tree
, proto_elasticsearch
, tvb
, 0, -1, ENC_NA
);
563 elasticsearch_tree
= proto_item_add_subtree(root_elasticsearch_item
,ett_elasticsearch
);
565 if(elasticsearch_binary_header_is_valid(tvb
)){
566 /* pass all packets through TCP-reassembly */
567 tcp_dissect_pdus(tvb
, pinfo
, elasticsearch_tree
, true, ELASTICSEARCH_HEADER_LENGTH
,
568 elasticsearch_get_binary_message_len
, elasticsearch_dissect_valid_binary_packet
, data
);
570 proto_tree_add_item(elasticsearch_tree
, hf_elasticsearch_data
, tvb
, offset
, -1, ENC_NA
);
571 expert_add_info(pinfo
, elasticsearch_tree
, &ei_elasticsearch_unsupported_version
);
574 return tvb_captured_length(tvb
);
577 void proto_register_elasticsearch(void) {
579 static hf_register_info hf
[] = {
580 { &hf_elasticsearch_internal_header
,
581 { "Internal header", "elasticsearch.internal_header",
587 { &hf_elasticsearch_version
,
588 { "Version", "elasticsearch.version",
589 FT_UINT32
, BASE_CUSTOM
,
590 CF_FUNC(elasticsearch_format_version
), 0x0,
594 { &hf_elasticsearch_ping_request_id
,
595 { "Ping ID", "elasticsearch.ping_request_id",
601 { &hf_elasticsearch_cluster_name
,
602 { "Cluster name", "elasticsearch.cluster_name",
603 FT_STRING
, BASE_NONE
,
608 { &hf_elasticsearch_node_name
,
609 { "Node name", "elasticsearch.node_name",
610 FT_STRING
, BASE_NONE
,
615 { &hf_elasticsearch_node_id
,
616 { "Node ID", "elasticsearch.node_id",
617 FT_STRING
, BASE_NONE
,
622 { &hf_elasticsearch_host_name
,
623 { "Hostname", "elasticsearch.host_name",
624 FT_STRING
, BASE_NONE
,
629 { &hf_elasticsearch_host_address
,
630 { "Host address", "elasticsearch.host_address",
631 FT_STRING
, BASE_NONE
,
636 { &hf_elasticsearch_address_type
,
637 { "Type", "elasticsearch.address.type",
639 VALS(address_types
), 0x0,
643 { &hf_elasticsearch_address_format
,
644 { "Format", "elasticsearch.address.format",
646 VALS(address_format
), 0x0,
650 { &hf_elasticsearch_address_name
,
651 { "Name", "elasticsearch.address.name",
652 FT_STRING
, BASE_NONE
,
657 { &hf_elasticsearch_address_length
,
658 { "Length", "elasticsearch.address.length",
664 { &hf_elasticsearch_address_ipv4
,
665 { "IP", "elasticsearch.address.ipv4",
671 { &hf_elasticsearch_address_ipv6
,
672 { "IP", "elasticsearch.address.ipv6",
678 { &hf_elasticsearch_address_ipv6_scope_id
,
679 { "IP", "elasticsearch.address.ipv6.scope_id",
685 { &hf_elasticsearch_address_port
,
686 { "Port", "elasticsearch.address.port",
692 { &hf_elasticsearch_attributes_length
,
693 { "Attributes length", "elasticsearch.attributes.length",
699 { &hf_elasticsearch_header_token
,
700 { "Token", "elasticsearch.header.token",
701 FT_STRING
, BASE_NONE
,
706 { &hf_elasticsearch_header_message_length
,
707 { "Message length", "elasticsearch.header.message_length",
713 { &hf_elasticsearch_header_request_id
,
714 { "Request ID", "elasticsearch.header.request_id",
720 { &hf_elasticsearch_header_status_flags
,
721 { "Status flags", "elasticsearch.header.status_flags",
727 { &hf_elasticsearch_header_status_flags_message_type
,
728 { "Message type", "elasticsearch.header.status_flags.message_type",
730 VALS(status_flag_message_type
), 0x0,
734 { &hf_elasticsearch_header_status_flags_error
,
735 { "Error", "elasticsearch.header.status_flags.error",
736 FT_BOOLEAN
, BASE_NONE
,
737 TFS(&tfs_set_notset
), 0x0,
741 { &hf_elasticsearch_header_status_flags_compression
,
742 { "Compression", "elasticsearch.header.status_flags.compression",
743 FT_BOOLEAN
, BASE_NONE
,
744 TFS(&tfs_set_notset
), 0x0,
748 { &hf_elasticsearch_header_size
,
749 { "Header size", "elasticsearch.header.size",
755 { &hf_elasticsearch_header_request
,
756 { "Request header", "elasticsearch.header.request",
757 FT_NONE
, BASE_NONE
, NULL
, 0x0,
760 { &hf_elasticsearch_header_response
,
761 { "Response header", "elasticsearch.header.response",
762 FT_NONE
, BASE_NONE
, NULL
, 0x0,
765 { &hf_elasticsearch_header_key
,
766 { "Key", "elasticsearch.header.key",
767 FT_STRING
, BASE_NONE
, NULL
, 0x0,
770 { &hf_elasticsearch_header_value
,
771 { "Value", "elasticsearch.header.value",
772 FT_STRING
, BASE_NONE
, NULL
, 0x0,
775 { &hf_elasticsearch_feature
,
776 { "Feature", "elasticsearch.feature",
777 FT_STRING
, BASE_NONE
, NULL
, 0x0,
780 { &hf_elasticsearch_action
,
781 { "Action", "elasticsearch.action",
782 FT_STRING
, BASE_NONE
,
787 { &hf_elasticsearch_data
,
788 { "Data", "elasticsearch.data",
794 { &hf_elasticsearch_data_compressed
,
795 { "Compressed data", "elasticsearch.data_compressed",
804 static int *ett
[] = {
806 &ett_elasticsearch_address
,
807 &ett_elasticsearch_discovery_node
,
808 &ett_elasticsearch_status_flags
,
809 &ett_elasticsearch_header
,
812 static ei_register_info ei
[] = {
813 { &ei_elasticsearch_unsupported_version
, { "elasticsearch.version.unsupported", PI_UNDECODED
, PI_WARN
, "Unsupported header type: Elasticsearch version < 0.20.0RC1", EXPFILL
}},
814 { &ei_elasticsearch_unsupported_address_format
, { "elasticsearch.address.format.unsupported", PI_MALFORMED
, PI_WARN
, "Unsupported address format", EXPFILL
}},
815 { &ei_elasticsearch_unsupported_address_type
, { "elasticsearch.address.type.unsupported", PI_MALFORMED
, PI_WARN
, "Unsupported address type", EXPFILL
}},
818 expert_module_t
*expert_elasticsearch
;
820 proto_elasticsearch
= proto_register_protocol("Elasticsearch", "Elasticsearch", "elasticsearch");
822 expert_elasticsearch
= expert_register_protocol(proto_elasticsearch
);
823 expert_register_field_array(expert_elasticsearch
, ei
, array_length(ei
));
825 proto_register_field_array(proto_elasticsearch
, hf
, array_length(hf
));
826 proto_register_subtree_array(ett
, array_length(ett
));
828 elasticsearch_handle_binary
= register_dissector("elasticsearch_binary", dissect_elasticsearch_binary
, proto_elasticsearch
);
829 elasticsearch_zen_handle
= register_dissector("elasticsearch_zen_ping", dissect_elasticsearch_zen_ping
, proto_elasticsearch
);
833 void proto_reg_handoff_elasticsearch(void) {
835 dissector_add_uint_with_preference("udp.port", ELASTICSEARCH_DISCOVERY_PORT
, elasticsearch_zen_handle
);
836 dissector_add_uint_with_preference("tcp.port", ELASTICSEARCH_BINARY_PORT
, elasticsearch_handle_binary
);
841 * Editor modelines - https://www.wireshark.org/tools/modelines.html
846 * indent-tabs-mode: nil
849 * vi: set shiftwidth=4 tabstop=8 expandtab:
850 * :indentSize=4:tabSize=8:noTabs=true: