2 * Routines for Gearman protocol packet disassembly
3 * By Flier Lu <flier.lu@gmail.com>
4 * Copyright 2010 Flier Lu
8 * http://gearman.org/protocol/
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * SPDX-License-Identifier: GPL-2.0-or-later
19 #include <epan/packet.h>
20 #include <epan/prefs.h>
21 #include <epan/expert.h>
22 #include <wsutil/array.h>
23 #include "packet-tcp.h"
25 void proto_register_gearman(void);
26 void proto_reg_handoff_gearman(void);
28 static dissector_handle_t gearman_handle
;
30 static int proto_gearman
;
32 static int hf_gearman_mgr_cmd
;
33 static int hf_gearman_magic_code
;
34 static int hf_gearman_pkt_type
;
35 static int hf_gearman_data_size
;
36 static int hf_gearman_data_content
;
37 static int hf_gearman_option_name
;
38 static int hf_gearman_func_name
;
39 static int hf_gearman_func_namez
;
40 static int hf_gearman_client_id
;
41 static int hf_gearman_client_count
;
42 static int hf_gearman_uniq_id
;
43 static int hf_gearman_uniq_idz
;
44 static int hf_gearman_argument
;
45 static int hf_gearman_job_handle
;
46 static int hf_gearman_job_handlez
;
47 static int hf_gearman_complete_numerator
;
48 static int hf_gearman_complete_denominator
;
49 static int hf_gearman_submit_job_sched_minute
;
50 static int hf_gearman_submit_job_sched_hour
;
51 static int hf_gearman_submit_job_sched_day_of_month
;
52 static int hf_gearman_submit_job_sched_month
;
53 static int hf_gearman_submit_job_sched_day_of_week
;
54 static int hf_gearman_submit_job_epoch_time
;
55 static int hf_gearman_reducer
;
56 static int hf_gearman_result
;
57 static int hf_gearman_known_status
;
58 static int hf_gearman_running_status
;
59 static int hf_gearman_timeout_value
;
60 static int hf_gearman_echo_text
;
61 static int hf_gearman_err_code
;
62 static int hf_gearman_err_text
;
64 static int ett_gearman
;
65 static int ett_gearman_command
;
66 static int ett_gearman_content
;
68 static expert_field ei_gearman_pkt_type_unknown
;
70 static bool gearman_desegment
= true;
72 static const int GEARMAN_COMMAND_HEADER_SIZE
= 12;
73 static const int GEARMAN_PORT
= 4730;
74 static const unsigned char *GEARMAN_MAGIC_CODE_REQUEST
= "\0REQ";
75 static const unsigned char *GEARMAN_MAGIC_CODE_RESPONSE
= "\0RES";
77 static const char *GEARMAN_MGR_CMDS
[] = {
85 static const int GEARMAN_MGR_CMDS_COUNT
= array_length(GEARMAN_MGR_CMDS
);
90 GEARMAN_COMMAND_CAN_DO
, /* W->J: FUNC */
91 GEARMAN_COMMAND_CANT_DO
, /* W->J: FUNC */
92 GEARMAN_COMMAND_RESET_ABILITIES
, /* W->J: -- */
93 GEARMAN_COMMAND_PRE_SLEEP
, /* W->J: -- */
94 GEARMAN_COMMAND_UNUSED
,
95 GEARMAN_COMMAND_NOOP
, /* J->W: -- */
96 GEARMAN_COMMAND_SUBMIT_JOB
, /* C->J: FUNC[0]UNIQ[0]ARGS */
97 GEARMAN_COMMAND_JOB_CREATED
, /* J->C: HANDLE */
98 GEARMAN_COMMAND_GRAB_JOB
, /* W->J: -- */
99 GEARMAN_COMMAND_NO_JOB
, /* J->W: -- */
100 GEARMAN_COMMAND_JOB_ASSIGN
, /* J->W: HANDLE[0]FUNC[0]ARG */
101 GEARMAN_COMMAND_WORK_STATUS
, /* W->J/C: HANDLE[0]NUMERATOR[0]DENOMINATOR */
102 GEARMAN_COMMAND_WORK_COMPLETE
, /* W->J/C: HANDLE[0]RES */
103 GEARMAN_COMMAND_WORK_FAIL
, /* W->J/C: HANDLE */
104 GEARMAN_COMMAND_GET_STATUS
, /* C->J: HANDLE */
105 GEARMAN_COMMAND_ECHO_REQ
, /* ?->J: TEXT */
106 GEARMAN_COMMAND_ECHO_RES
, /* J->?: TEXT */
107 GEARMAN_COMMAND_SUBMIT_JOB_BG
, /* C->J: FUNC[0]UNIQ[0]ARGS */
108 GEARMAN_COMMAND_ERROR
, /* J->?: ERRCODE[0]ERR_TEXT */
109 GEARMAN_COMMAND_STATUS_RES
, /* C->J: HANDLE[0]KNOWN[0]RUNNING[0]NUM[0]DENOM */
110 GEARMAN_COMMAND_SUBMIT_JOB_HIGH
, /* C->J: FUNC[0]UNIQ[0]ARGS */
111 GEARMAN_COMMAND_SET_CLIENT_ID
, /* W->J: [RANDOM_STRING_NO_WHITESPACE] */
112 GEARMAN_COMMAND_CAN_DO_TIMEOUT
, /* W->J: FUNC[0]TIMEOUT */
113 GEARMAN_COMMAND_ALL_YOURS
,
114 GEARMAN_COMMAND_WORK_EXCEPTION
,
115 GEARMAN_COMMAND_OPTION_REQ
,
116 GEARMAN_COMMAND_OPTION_RES
,
117 GEARMAN_COMMAND_WORK_DATA
,
118 GEARMAN_COMMAND_WORK_WARNING
,
119 GEARMAN_COMMAND_GRAB_JOB_UNIQ
,
120 GEARMAN_COMMAND_JOB_ASSIGN_UNIQ
,
121 GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG
,
122 GEARMAN_COMMAND_SUBMIT_JOB_LOW
,
123 GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG
,
124 GEARMAN_COMMAND_SUBMIT_JOB_SCHED
,
125 GEARMAN_COMMAND_SUBMIT_JOB_EPOCH
,
126 GEARMAN_COMMAND_SUBMIT_REDUCE_JOB
, /* C->J: FUNC[0]UNIQ[0]REDUCER[0]UNUSED[0]ARGS */
127 GEARMAN_COMMAND_SUBMIT_REDUCE_JOB_BG
, /* C->J: FUNC[0]UNIQ[0]REDUCER[0]UNUSED[0]ARGS */
128 GEARMAN_COMMAND_GRAB_JOB_ALL
, /* W->J -- */
129 GEARMAN_COMMAND_JOB_ASSIGN_ALL
, /* J->W: HANDLE[0]FUNC[0]UNIQ[0]REDUCER[0]ARGS */
130 GEARMAN_COMMAND_GET_STATUS_UNIQUE
, /* C->J: UNIQUE */
131 GEARMAN_COMMAND_STATUS_RES_UNIQUE
, /* J->C: UNIQUE[0]KNOWN[0]RUNNING[0]NUM[0]DENOM[0]CLIENT_COUNT */
132 GEARMAN_COMMAND_MAX
/* Always add new commands before this. */
135 static const value_string gearman_command_names
[] = {
136 { GEARMAN_COMMAND_TEXT
, "TEXT" },
137 { GEARMAN_COMMAND_CAN_DO
, "CAN_DO" }, /* W->J: FUNC */
138 { GEARMAN_COMMAND_CANT_DO
, "CANT_DO" }, /* W->J: FUNC */
139 { GEARMAN_COMMAND_RESET_ABILITIES
, "RESET_ABILITIES" }, /* W->J: -- */
140 { GEARMAN_COMMAND_PRE_SLEEP
, "PRE_SLEEP" }, /* W->J: -- */
141 { GEARMAN_COMMAND_UNUSED
, "UNUSED" },
142 { GEARMAN_COMMAND_NOOP
, "NOOP" }, /* J->W: -- */
143 { GEARMAN_COMMAND_SUBMIT_JOB
, "SUBMIT_JOB" }, /* C->J: FUNC[0]UNIQ[0]ARGS */
144 { GEARMAN_COMMAND_JOB_CREATED
, "JOB_CREATED" }, /* J->C: HANDLE */
145 { GEARMAN_COMMAND_GRAB_JOB
, "GRAB_JOB" }, /* W->J: -- */
146 { GEARMAN_COMMAND_NO_JOB
, "NO_JOB" }, /* J->W: -- */
147 { GEARMAN_COMMAND_JOB_ASSIGN
, "JOB_ASSIGN" }, /* J->W: HANDLE[0]FUNC[0]ARG */
148 { GEARMAN_COMMAND_WORK_STATUS
, "WORK_STATUS" }, /* W->J/C: HANDLE[0]NUMERATOR[0]DENOMINATOR */
149 { GEARMAN_COMMAND_WORK_COMPLETE
, "WORK_COMPLETE" }, /* W->J/C: HANDLE[0]RES */
150 { GEARMAN_COMMAND_WORK_FAIL
, "WORK_FAIL" }, /* W->J/C: HANDLE */
151 { GEARMAN_COMMAND_GET_STATUS
, "GET_STATUS" }, /* C->J: HANDLE */
152 { GEARMAN_COMMAND_ECHO_REQ
, "ECHO_REQ" }, /* ?->J: TEXT */
153 { GEARMAN_COMMAND_ECHO_RES
, "ECHO_RES" }, /* J->?: TEXT */
154 { GEARMAN_COMMAND_SUBMIT_JOB_BG
, "SUBMIT_JOB_BG" }, /* C->J: FUNC[0]UNIQ[0]ARGS */
155 { GEARMAN_COMMAND_ERROR
, "ERROR" }, /* J->?: ERRCODE[0]ERR_TEXT */
156 { GEARMAN_COMMAND_STATUS_RES
, "STATUS_RES" }, /* C->J: HANDLE[0]KNOWN[0]RUNNING[0]NUM[0]DENOM */
157 { GEARMAN_COMMAND_SUBMIT_JOB_HIGH
, "SUBMIT_JOB_HIGH" }, /* C->J: FUNC[0]UNIQ[0]ARGS */
158 { GEARMAN_COMMAND_SET_CLIENT_ID
, "SET_CLIENT_ID" }, /* W->J: [RANDOM_STRING_NO_WHITESPACE] */
159 { GEARMAN_COMMAND_CAN_DO_TIMEOUT
, "CAN_DO_TIMEOUT" }, /* W->J: FUNC[0]TIMEOUT */
160 { GEARMAN_COMMAND_ALL_YOURS
, "ALL_YOURS" },
161 { GEARMAN_COMMAND_WORK_EXCEPTION
, "WORK_EXCEPTION" },
162 { GEARMAN_COMMAND_OPTION_REQ
, "OPTION_REQ" },
163 { GEARMAN_COMMAND_OPTION_RES
, "OPTION_RES" },
164 { GEARMAN_COMMAND_WORK_DATA
, "WORK_DATA" },
165 { GEARMAN_COMMAND_WORK_WARNING
, "WORK_WARNING" },
166 { GEARMAN_COMMAND_GRAB_JOB_UNIQ
, "GRAB_JOB_UNIQ" },
167 { GEARMAN_COMMAND_JOB_ASSIGN_UNIQ
, "JOB_ASSIGN_UNIQ" },
168 { GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG
, "SUBMIT_JOB_HIGH_BG" },
169 { GEARMAN_COMMAND_SUBMIT_JOB_LOW
, "SUBMIT_JOB_LOW" },
170 { GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG
, "SUBMIT_JOB_LOW_BG" },
171 { GEARMAN_COMMAND_SUBMIT_JOB_SCHED
, "SUBMIT_JOB_SCHED" },
172 { GEARMAN_COMMAND_SUBMIT_JOB_EPOCH
, "SUBMIT_JOB_EPOCH" },
173 { GEARMAN_COMMAND_SUBMIT_REDUCE_JOB
, "SUBMIT_REDUCE_JOB" },
174 { GEARMAN_COMMAND_SUBMIT_REDUCE_JOB_BG
, "SUBMIT_REDUCE_JOB_BG" },
175 { GEARMAN_COMMAND_GRAB_JOB_ALL
, "GRAB_JOB_ALL" },
176 { GEARMAN_COMMAND_JOB_ASSIGN_ALL
, "JOB_ASSIGN_ALL" },
177 { GEARMAN_COMMAND_GET_STATUS_UNIQUE
, "GET_STATUS_UNIQUE" },
178 { GEARMAN_COMMAND_STATUS_RES_UNIQUE
, "STATUS_RES_UNIQUE" },
183 get_gearman_pdu_len(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
, void *data _U_
)
185 return tvb_get_ntohl(tvb
, offset
+8)+GEARMAN_COMMAND_HEADER_SIZE
;
189 dissect_binary_packet(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
195 proto_item
*content_item
= NULL
;
196 proto_tree
*content_tree
= NULL
;
198 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Gearman");
199 col_clear(pinfo
->cinfo
,COL_INFO
);
201 magic_code
= tvb_get_string_enc(pinfo
->pool
, tvb
, 1, 3, ENC_ASCII
);
202 type
= tvb_get_ntohl(tvb
, 4);
203 size
= tvb_get_ntohl(tvb
, 8);
205 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, " , ", "[%s] ", magic_code
);
207 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s(%d) LEN=%d",
208 val_to_str(type
, gearman_command_names
, "Unknown (0x%08x)"), type
, size
);
212 proto_tree
*command_tree
, *gearman_tree
;
213 ti
= proto_tree_add_item(tree
, proto_gearman
, tvb
, 0, -1, ENC_NA
);
214 gearman_tree
= proto_item_add_subtree(ti
, ett_gearman
);
216 command_tree
= proto_tree_add_subtree_format(gearman_tree
, tvb
, 0, GEARMAN_COMMAND_HEADER_SIZE
+size
, ett_gearman_command
, NULL
,
217 "[%s] %s(%d) LEN=%d", magic_code
, val_to_str(type
, gearman_command_names
, "Unknown (0x%08x)"), type
, size
);
219 proto_tree_add_string(command_tree
, hf_gearman_magic_code
, tvb
, 0, 4, magic_code
);
220 proto_tree_add_item(command_tree
, hf_gearman_pkt_type
, tvb
, 4, 4, ENC_BIG_ENDIAN
);
221 proto_tree_add_item(command_tree
, hf_gearman_data_size
, tvb
, 8, 4, ENC_BIG_ENDIAN
);
223 // explicitly set len to 0 if there are no arguments,
224 // else use tvb_strnlen() to find the remaining length of tvb
225 len
= ( size
> 0 ) ? tvb_strnlen( tvb
, GEARMAN_COMMAND_HEADER_SIZE
, -1 ) : 0 ;
226 content_item
= proto_tree_add_item(command_tree
, hf_gearman_data_content
, tvb
, GEARMAN_COMMAND_HEADER_SIZE
, len
, ENC_ASCII
);
227 content_tree
= proto_item_add_subtree(content_item
, ett_gearman_content
);
230 curr_offset
= GEARMAN_COMMAND_HEADER_SIZE
;
236 // when determining len for proto_tree_add_item()
238 // if the command has one argument:
239 // - use tvb_strnlen()
241 // if the command has multiple arguments:
242 // - use tvb_strsize() for the all but the last argument
243 // - use tvb_strnlen() for the last argument
245 // These are *not* null-terminated strings, they're null-separated
246 // strings. For example, some arguments might be the last argument
247 // in some commands and not be the last argument in other commands,
248 // so they're not always followed by a null.
251 // commands with a single argument
254 case GEARMAN_COMMAND_ECHO_REQ
:
255 case GEARMAN_COMMAND_ECHO_RES
:
257 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
258 proto_tree_add_item(content_tree
, hf_gearman_echo_text
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
261 case GEARMAN_COMMAND_JOB_CREATED
:
262 case GEARMAN_COMMAND_WORK_FAIL
:
264 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
265 proto_tree_add_item(content_tree
, hf_gearman_job_handle
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
268 case GEARMAN_COMMAND_OPTION_REQ
:
269 case GEARMAN_COMMAND_OPTION_RES
:
271 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
272 proto_tree_add_item(content_tree
, hf_gearman_option_name
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
275 case GEARMAN_COMMAND_SET_CLIENT_ID
:
277 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
278 proto_tree_add_item(content_tree
, hf_gearman_client_id
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
281 case GEARMAN_COMMAND_GET_STATUS_UNIQUE
:
283 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
284 proto_tree_add_item(content_tree
, hf_gearman_uniq_id
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
287 case GEARMAN_COMMAND_CAN_DO
:
288 case GEARMAN_COMMAND_CANT_DO
:
290 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
291 proto_tree_add_item(content_tree
, hf_gearman_func_name
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
295 // commands with multiple arguments
298 case GEARMAN_COMMAND_ERROR
:
300 len
= tvb_strsize(tvb
, curr_offset
);
301 proto_tree_add_item(content_tree
, hf_gearman_err_code
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
304 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
305 proto_tree_add_item(content_tree
, hf_gearman_err_text
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
308 case GEARMAN_COMMAND_WORK_DATA
:
309 case GEARMAN_COMMAND_WORK_WARNING
:
310 case GEARMAN_COMMAND_WORK_COMPLETE
:
311 case GEARMAN_COMMAND_WORK_EXCEPTION
:
313 len
= tvb_strsize(tvb
, curr_offset
);
314 proto_tree_add_item(content_tree
, hf_gearman_job_handlez
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
317 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
318 proto_tree_add_item(content_tree
, hf_gearman_result
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
321 case GEARMAN_COMMAND_STATUS_RES
:
323 len
= tvb_strsize(tvb
, curr_offset
);
324 proto_tree_add_item(content_tree
, hf_gearman_job_handlez
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
327 len
= tvb_strsize(tvb
, curr_offset
);
328 proto_tree_add_item(content_tree
, hf_gearman_known_status
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
331 len
= tvb_strsize(tvb
, curr_offset
);
332 proto_tree_add_item(content_tree
, hf_gearman_running_status
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
335 len
= tvb_strsize(tvb
, curr_offset
);
336 proto_tree_add_item(content_tree
, hf_gearman_complete_numerator
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
339 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
340 proto_tree_add_item(content_tree
, hf_gearman_complete_denominator
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
343 case GEARMAN_COMMAND_SUBMIT_JOB
:
344 case GEARMAN_COMMAND_SUBMIT_JOB_BG
:
345 case GEARMAN_COMMAND_SUBMIT_JOB_HIGH
:
346 case GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG
:
347 case GEARMAN_COMMAND_SUBMIT_JOB_LOW
:
348 case GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG
:
350 len
= tvb_strsize(tvb
, curr_offset
);
351 proto_tree_add_item(content_tree
, hf_gearman_func_namez
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
354 len
= tvb_strsize(tvb
, curr_offset
);
355 proto_tree_add_item(content_tree
, hf_gearman_uniq_idz
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
358 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
359 proto_tree_add_item(content_tree
, hf_gearman_argument
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
362 case GEARMAN_COMMAND_SUBMIT_REDUCE_JOB
:
363 case GEARMAN_COMMAND_SUBMIT_REDUCE_JOB_BG
:
365 len
= tvb_strsize(tvb
, curr_offset
);
366 proto_tree_add_item(content_tree
, hf_gearman_func_namez
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
369 len
= tvb_strsize(tvb
, curr_offset
);
370 proto_tree_add_item(content_tree
, hf_gearman_uniq_idz
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
373 len
= tvb_strsize(tvb
, curr_offset
);
374 proto_tree_add_item(content_tree
, hf_gearman_reducer
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
377 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
378 proto_tree_add_item(content_tree
, hf_gearman_argument
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
381 case GEARMAN_COMMAND_SUBMIT_JOB_SCHED
:
383 len
= tvb_strsize(tvb
, curr_offset
);
384 proto_tree_add_item(content_tree
, hf_gearman_func_namez
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
387 len
= tvb_strsize(tvb
, curr_offset
);
388 proto_tree_add_item(content_tree
, hf_gearman_uniq_idz
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
391 len
= tvb_strsize(tvb
, curr_offset
);
392 proto_tree_add_item(content_tree
, hf_gearman_submit_job_sched_minute
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
395 len
= tvb_strsize(tvb
, curr_offset
);
396 proto_tree_add_item(content_tree
, hf_gearman_submit_job_sched_hour
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
399 len
= tvb_strsize(tvb
, curr_offset
);
400 proto_tree_add_item(content_tree
, hf_gearman_submit_job_sched_day_of_month
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
403 len
= tvb_strsize(tvb
, curr_offset
);
404 proto_tree_add_item(content_tree
, hf_gearman_submit_job_sched_month
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
407 len
= tvb_strsize(tvb
, curr_offset
);
408 proto_tree_add_item(content_tree
, hf_gearman_submit_job_sched_day_of_week
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
411 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
412 proto_tree_add_item(content_tree
, hf_gearman_argument
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
415 case GEARMAN_COMMAND_SUBMIT_JOB_EPOCH
:
417 len
= tvb_strsize(tvb
, curr_offset
);
418 proto_tree_add_item(content_tree
, hf_gearman_func_namez
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
421 len
= tvb_strsize(tvb
, curr_offset
);
422 proto_tree_add_item(content_tree
, hf_gearman_uniq_idz
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
425 len
= tvb_strsize(tvb
, curr_offset
);
426 proto_tree_add_item(content_tree
, hf_gearman_submit_job_epoch_time
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
429 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
430 proto_tree_add_item(content_tree
, hf_gearman_argument
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
433 case GEARMAN_COMMAND_JOB_ASSIGN
:
434 len
= tvb_strsize(tvb
, curr_offset
);
435 proto_tree_add_item(content_tree
, hf_gearman_job_handlez
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
438 len
= tvb_strsize(tvb
, curr_offset
);
439 proto_tree_add_item(content_tree
, hf_gearman_func_namez
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
442 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
443 proto_tree_add_item(content_tree
, hf_gearman_argument
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
446 case GEARMAN_COMMAND_JOB_ASSIGN_UNIQ
:
447 len
= tvb_strsize(tvb
, curr_offset
);
448 proto_tree_add_item(content_tree
, hf_gearman_job_handlez
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
451 len
= tvb_strsize(tvb
, curr_offset
);
452 proto_tree_add_item(content_tree
, hf_gearman_func_namez
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
455 len
= tvb_strsize(tvb
, curr_offset
);
456 proto_tree_add_item(content_tree
, hf_gearman_uniq_idz
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
459 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
460 proto_tree_add_item(content_tree
, hf_gearman_argument
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
463 case GEARMAN_COMMAND_JOB_ASSIGN_ALL
:
465 len
= tvb_strsize(tvb
, curr_offset
);
466 proto_tree_add_item(content_tree
, hf_gearman_job_handlez
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
469 len
= tvb_strsize(tvb
, curr_offset
);
470 proto_tree_add_item(content_tree
, hf_gearman_func_namez
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
473 len
= tvb_strsize(tvb
, curr_offset
);
474 proto_tree_add_item(content_tree
, hf_gearman_uniq_idz
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
477 len
= tvb_strsize(tvb
, curr_offset
);
478 proto_tree_add_item(content_tree
, hf_gearman_reducer
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
481 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
482 proto_tree_add_item(content_tree
, hf_gearman_argument
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
485 case GEARMAN_COMMAND_WORK_STATUS
:
487 len
= tvb_strsize(tvb
, curr_offset
);
488 proto_tree_add_item(content_tree
, hf_gearman_job_handlez
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
491 len
= tvb_strsize(tvb
, curr_offset
);
492 proto_tree_add_item(content_tree
, hf_gearman_complete_numerator
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
495 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
496 proto_tree_add_item(content_tree
, hf_gearman_complete_denominator
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
499 case GEARMAN_COMMAND_CAN_DO_TIMEOUT
:
501 len
= tvb_strsize(tvb
, curr_offset
);
502 proto_tree_add_item(content_tree
, hf_gearman_func_namez
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
505 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
506 proto_tree_add_item(content_tree
, hf_gearman_timeout_value
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
509 case GEARMAN_COMMAND_STATUS_RES_UNIQUE
:
511 len
= tvb_strsize(tvb
, curr_offset
);
512 proto_tree_add_item(content_tree
, hf_gearman_job_handlez
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
515 len
= tvb_strsize(tvb
, curr_offset
);
516 proto_tree_add_item(content_tree
, hf_gearman_known_status
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
519 len
= tvb_strsize(tvb
, curr_offset
);
520 proto_tree_add_item(content_tree
, hf_gearman_running_status
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
523 len
= tvb_strsize(tvb
, curr_offset
);
524 proto_tree_add_item(content_tree
, hf_gearman_complete_numerator
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
527 len
= tvb_strsize(tvb
, curr_offset
);
528 proto_tree_add_item(content_tree
, hf_gearman_complete_denominator
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
531 len
= tvb_strnlen( tvb
, curr_offset
, -1 );
532 proto_tree_add_item(content_tree
, hf_gearman_client_count
, tvb
, curr_offset
, len
, ENC_NA
|ENC_ASCII
);
537 expert_add_info(pinfo
, content_item
, &ei_gearman_pkt_type_unknown
);
540 col_set_fence(pinfo
->cinfo
, COL_INFO
);
541 return tvb_captured_length(tvb
);
545 dissect_management_packet(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
547 int i
, type
= 0, cmdlen
, linelen
, offset
= 0, next_offset
= 0;
549 proto_tree
*gearman_tree
;
551 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Gearman");
552 col_clear(pinfo
->cinfo
, COL_INFO
);
554 ti
= proto_tree_add_item(tree
, proto_gearman
, tvb
, 0, -1, ENC_NA
);
555 gearman_tree
= proto_item_add_subtree(ti
, ett_gearman
);
557 while ((linelen
= tvb_find_line_end(tvb
, offset
, -1, &next_offset
, false)) > 0)
559 for (i
=0; i
<GEARMAN_MGR_CMDS_COUNT
; i
++)
561 /* the array is a const and clearly none of the elements are longer than
562 * MAX_SIGNED_INT so this is a safe cast */
563 cmdlen
= (int)strlen(GEARMAN_MGR_CMDS
[i
]);
565 if (cmdlen
== linelen
&& 0 == tvb_strneql(tvb
, offset
, GEARMAN_MGR_CMDS
[i
], cmdlen
))
567 const uint8_t* cmdstr
;
568 proto_tree_add_item_ret_string(gearman_tree
, hf_gearman_mgr_cmd
, tvb
, offset
, cmdlen
, ENC_ASCII
|ENC_NA
, pinfo
->pool
, &cmdstr
);
569 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "[MGR] %s", cmdstr
);
575 if (GEARMAN_MGR_CMDS_COUNT
== i
)
577 proto_tree_add_format_text(gearman_tree
, tvb
, offset
, next_offset
- offset
);
581 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "[MGR] %s", tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, linelen
, ENC_ASCII
));
586 col_append_sep_str(pinfo
->cinfo
, COL_INFO
, ",", tvb_get_string_enc(pinfo
->pool
, tvb
, offset
, linelen
, ENC_ASCII
));
590 offset
= next_offset
;
595 dissect_gearman(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data
)
597 if ((0 == tvb_memeql(tvb
, 0, GEARMAN_MAGIC_CODE_REQUEST
, 4)) ||
598 (0 == tvb_memeql(tvb
, 0, GEARMAN_MAGIC_CODE_RESPONSE
, 4)))
600 tcp_dissect_pdus(tvb
, pinfo
, tree
, gearman_desegment
, GEARMAN_COMMAND_HEADER_SIZE
, get_gearman_pdu_len
, dissect_binary_packet
, data
);
604 dissect_management_packet(tvb
, pinfo
, tree
);
607 return tvb_captured_length(tvb
);
611 proto_register_gearman(void)
613 static hf_register_info hf
[] = {
614 { &hf_gearman_mgr_cmd
, { "Management Command", "gearman.mgr_cmd", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
615 { &hf_gearman_magic_code
, { "Magic Code", "gearman.magic_code", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
616 { &hf_gearman_pkt_type
, { "Packet Type", "gearman.pkt_type", FT_UINT32
, BASE_DEC_HEX
, VALS(gearman_command_names
), 0x0, NULL
, HFILL
} },
617 { &hf_gearman_data_size
, { "Data Length", "gearman.data_size", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
618 { &hf_gearman_data_content
, { "Data Content", "gearman.data_content", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
619 { &hf_gearman_option_name
, { "Option Name", "gearman.opt.name", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
620 { &hf_gearman_func_name
, { "Function Name", "gearman.func.name", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
621 { &hf_gearman_func_namez
, { "Function Name", "gearman.func.name", FT_STRINGZ
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
622 { &hf_gearman_client_id
, { "Client ID", "gearman.client_id", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
623 { &hf_gearman_client_count
, { "Client Count", "gearman.client_count", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
624 { &hf_gearman_uniq_id
, { "Unique ID", "gearman.uniq_id", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
625 { &hf_gearman_uniq_idz
, { "Unique ID", "gearman.uniq_id", FT_STRINGZ
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
626 { &hf_gearman_argument
, { "Function Argument", "gearman.func.arg", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
627 { &hf_gearman_job_handle
, { "Job Handle", "gearman.job.handle", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
628 { &hf_gearman_job_handlez
, { "Job Handle", "gearman.job.handle", FT_STRINGZ
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
629 { &hf_gearman_complete_numerator
, { "Complete Numerator", "gearman.numerator", FT_STRINGZ
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
630 { &hf_gearman_complete_denominator
, { "Complete Denominator", "gearman.denominator", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
631 { &hf_gearman_submit_job_sched_minute
, { "Minute", "gearman.submit_job_sched.minute", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
632 { &hf_gearman_submit_job_sched_hour
, { "Hour", "gearman.submit_job_sched.hour", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
633 { &hf_gearman_submit_job_sched_day_of_month
, { "Day of Month", "gearman.submit_job_sched.day_of_month", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
634 { &hf_gearman_submit_job_sched_month
, { "Month", "gearman.submit_job_sched.month", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
635 { &hf_gearman_submit_job_sched_day_of_week
, { "Day of Week", "gearman.submit_job_sched.day_of_week", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
636 { &hf_gearman_submit_job_epoch_time
, { "Epoch Time", "gearman.submit_job.epoch_time", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
637 { &hf_gearman_reducer
, { "Reducer", "gearman.reducer", FT_STRINGZ
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
638 { &hf_gearman_result
, { "Function Result", "gearman.func.result", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
639 { &hf_gearman_known_status
, { "Known job", "gearman.job.known", FT_STRINGZ
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
640 { &hf_gearman_running_status
, { "Running Job", "gearman.job.running", FT_STRINGZ
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
641 { &hf_gearman_timeout_value
, { "Timeout Value", "gearman.timeout.value", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
642 { &hf_gearman_echo_text
, { "Echo Text", "gearman.echo_text", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
643 { &hf_gearman_err_code
, { "Error Code", "gearman.err.code", FT_STRINGZ
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
644 { &hf_gearman_err_text
, { "Error Text", "gearman.err.text", FT_STRINGZ
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} }
647 /* Setup protocol subtree array */
648 static int *ett
[] = {
650 &ett_gearman_command
,
654 static ei_register_info ei
[] = {
655 { &ei_gearman_pkt_type_unknown
, { "gearman.pkt_type.unknown", PI_PROTOCOL
, PI_WARN
, "Unknown command", EXPFILL
}},
658 module_t
*gearman_module
;
659 expert_module_t
* expert_gearman
;
661 proto_gearman
= proto_register_protocol("Gearman Protocol", "Gearman", "gearman");
663 proto_register_field_array(proto_gearman
, hf
, array_length(hf
));
664 proto_register_subtree_array(ett
, array_length(ett
));
665 expert_gearman
= expert_register_protocol(proto_gearman
);
666 expert_register_field_array(expert_gearman
, ei
, array_length(ei
));
668 gearman_module
= prefs_register_protocol(proto_gearman
, NULL
);
669 prefs_register_bool_preference(gearman_module
, "desegment",
670 "Desegment all Gearman messages spanning multiple TCP segments",
671 "Whether the Gearman dissector should desegment all messages spanning multiple TCP segments",
674 gearman_handle
= register_dissector("gearman", dissect_gearman
, proto_gearman
);
678 proto_reg_handoff_gearman(void)
680 dissector_add_uint_with_preference("tcp.port", GEARMAN_PORT
, gearman_handle
);
684 * Editor modelines - https://www.wireshark.org/tools/modelines.html
689 * indent-tabs-mode: nil
692 * vi: set shiftwidth=2 tabstop=8 expandtab:
693 * :indentSize=2:tabSize=8:noTabs=true: