/src/wireshark/epan/dissectors/packet-saprouter.c
Line | Count | Source |
1 | | /* packet-saprouter.c |
2 | | * Routines for SAP Router dissection |
3 | | * Copyright 2022, Martin Gallo <martin.gallo [AT] gmail.com> |
4 | | * Code contributed by SecureAuth Corp. |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | */ |
12 | | |
13 | | /* |
14 | | * This is a dissector for the SAP Router protocol. |
15 | | * |
16 | | * Some details and example requests can be found in pysap's documentation: https://pysap.readthedocs.io/en/latest/protocols/SAPRouter.html. |
17 | | */ |
18 | | |
19 | | #include <config.h> |
20 | | #include <stdlib.h> |
21 | | |
22 | | #include <epan/packet.h> |
23 | | #include <epan/prefs.h> |
24 | | #include <epan/expert.h> |
25 | | #include <wsutil/wmem/wmem.h> |
26 | | #include <epan/conversation.h> |
27 | | #include <epan/credentials.h> |
28 | | #include <epan/tap.h> |
29 | | |
30 | | #include "packet-sapni.h" |
31 | | #include "packet-sapsnc.h" |
32 | | |
33 | | |
34 | | /* Define default ports */ |
35 | 16 | #define SAPROUTER_PORT_RANGE "3298-3299" |
36 | | |
37 | | /* |
38 | | * Length of the frame header |
39 | | */ |
40 | | #define SAPROUTER_HEADER_LEN 8 |
41 | | |
42 | | /* |
43 | | * Offsets of header fields |
44 | | */ |
45 | 0 | #define SAPROUTER_ROUTE_LENGTH_OFFSET 16 |
46 | 0 | #define SAPROUTER_ROUTE_OFFSET_OFFSET 20 |
47 | | |
48 | | /* SAP Router Eye Catcher strings */ |
49 | 0 | #define SAPROUTER_TYPE_NIPING_STRING "EYECATCHER" |
50 | 0 | #define SAPROUTER_TYPE_ROUTE_STRING "NI_ROUTE" |
51 | 0 | #define SAPROUTER_TYPE_ROUTE_ACCEPT "NI_PONG" |
52 | 0 | #define SAPROUTER_TYPE_ERR_STRING "NI_RTERR" |
53 | 0 | #define SAPROUTER_TYPE_ADMIN_STRING "ROUTER_ADM" |
54 | 0 | #define SAPROUTER_ERR_FIXED_LEN 12U |
55 | | |
56 | | /* SAP Router Talk Modes */ |
57 | | static const value_string saprouter_talk_mode_vals[] = { |
58 | | { 0, "NI_MSG_IO" }, |
59 | | { 1, "NI_RAW_IO" }, |
60 | | { 2, "NI_ROUT_IO" }, |
61 | | /* NULL */ |
62 | | { 0, NULL}, |
63 | | }; |
64 | | |
65 | | /* SAP Router Operation values */ |
66 | | static const value_string saprouter_opcode_vals[] = { |
67 | | { 0, "Error information" }, |
68 | | { 1, "Version Request" }, |
69 | | { 2, "Version Response" }, |
70 | | { 5, "Send Handle (5)" }, /* TODO: Check this opcodes */ |
71 | | { 6, "Send Handle (6)" }, /* TODO: Check this opcodes */ |
72 | | { 8, "Send Handle (8)" }, /* TODO: Check this opcodes */ |
73 | | { 70, "SNC request" }, /* TODO: Check this opcodes NiSncOpcode: NISNC_REQ */ |
74 | | { 71, "SNC handshake complete" }, /* TODO: Check this opcodes NiSncOpcode: NISNC_ACK */ |
75 | | /* NULL */ |
76 | | { 0, NULL} |
77 | | }; |
78 | | |
79 | | /* SAP Router Return Code values (as per SAP Note 63342 https://launchpad.support.sap.com/#/notes/63342) */ |
80 | | static const value_string saprouter_return_code_vals[] = { |
81 | | { -1, "NI-internal error (NIEINTERN)" }, |
82 | | { -2, "Host name unknown (NIEHOST_UNKNOWN)" }, |
83 | | { -3, "Service unknown (NIESERV_UNKNOWN)" }, |
84 | | { -4, "Service already used (NIESERV_USED)" }, |
85 | | { -5, "Time limit reached (NIETIMEOUT)" }, |
86 | | { -6, "Connection to partner broken (NIECONN_BROKEN)" }, |
87 | | { -7, "Data range too small (NIETOO_SMALL)" }, |
88 | | { -8, "Invalid parameters (NIEINVAL)" }, |
89 | | { -9, "Wake-Up (without data) (NIEWAKEUP)" }, |
90 | | {-10, "Connection setup failed (NIECONN_REFUSED)" }, |
91 | | {-11, "PING/PONG signal received (NIEPING)" }, |
92 | | {-12, "Connection to partner via NiRouter not yet set up (NIECONN_PENDING)" }, |
93 | | {-13, "Invalid version (NIEVERSION)" }, |
94 | | {-14, "Local hostname cannot be found (NIEMYHOSTNAME)" }, |
95 | | {-15, "No free port in range (NIENOFREEPORT)" }, |
96 | | {-16, "Local hostname invalid (NIEMYHOST_VERIFY)" }, |
97 | | {-17, "Error in the SNC shift in the saprouter ==> (NIESNC_FAILURE)" }, |
98 | | {-18, "Opcode received (NIEOPCODE)" }, |
99 | | {-19, "queue limit reached, next package not accepted (NIEQUE_FULL)" }, |
100 | | {-20, "Requested package too large (NIETOO_BIG)" }, |
101 | | {-90, "Host name unknown (NIEROUT_HOST_UNKNOWN)" }, |
102 | | {-91, "Service unknown (NIEROUT_SERV_UNKNOWN)" }, |
103 | | {-92, "Connection setup failed (NIEROUT_CONN_REFUSED)" }, |
104 | | {-93, "NI-internal errors (NIEROUT_INTERN)" }, |
105 | | {-94, "Connect from source to destination not allowed (NIEROUT_PERM_DENIED)" }, |
106 | | {-95, "Connection terminated (NIEROUT_CONN_BROKEN)" }, |
107 | | {-96, "Invalid client version (NIEROUT_VERSION)" }, |
108 | | {-97, "Connection cancelled by administrator (NIEROUT_CANCELED)" }, |
109 | | {-98, "saprouter shutdown (NIEROUT_SHUTDOWN)" }, |
110 | | {-99, "Information request refused (NIEROUT_INFO_DENIED)" }, |
111 | | {-100, "Max. number of clients reached (NIEROUT_OVERFLOW)" }, |
112 | | {-101, "Talkmode not allowed (NIEROUT_MODE_DENIED)" }, |
113 | | {-102, "Client not available (NIEROUT_NOCLIENT)" }, |
114 | | {-103, "Error in external library (NIEROUT_EXTERN)" }, |
115 | | {-104, "Error in the SNC shift (NIEROUT_SNC_FAILURE)" }, |
116 | | /* NULL */ |
117 | | { 0, NULL} |
118 | | }; |
119 | | |
120 | | |
121 | | /* SAP Router Admin Command values */ |
122 | | static const value_string saprouter_admin_command_vals[] = { |
123 | | { 2, "Information Request" }, |
124 | | { 3, "New Route Table Request" }, |
125 | | { 4, "Toggle Trace Request" }, |
126 | | { 5, "Stop Request" }, |
127 | | { 6, "Cancel Route Request" }, |
128 | | { 7, "Dump Buffers Request" }, |
129 | | { 8, "Flush Buffers Request" }, |
130 | | { 9, "Soft Shutdown Request" }, |
131 | | { 10, "Set Trace Peer" }, |
132 | | { 11, "Clear Trace Peer" }, |
133 | | { 12, "Trace Connection" }, |
134 | | { 13, "Trace Connection" }, |
135 | | { 14, "Hide Error Information Request" }, |
136 | | /* NULL */ |
137 | | { 0, NULL} |
138 | | }; |
139 | | |
140 | | static int credentials_tap; |
141 | | |
142 | | static int proto_saprouter; |
143 | | |
144 | | /* General fields */ |
145 | | static int hf_saprouter_type; |
146 | | static int hf_saprouter_ni_version; |
147 | | |
148 | | /* Niping messages */ |
149 | | static int hf_saprouter_niping_message; |
150 | | |
151 | | /* Route information */ |
152 | | static int hf_saprouter_route_version; |
153 | | static int hf_saprouter_entries; |
154 | | static int hf_saprouter_talk_mode; |
155 | | static int hf_saprouter_rest_nodes; |
156 | | static int hf_saprouter_route_length; |
157 | | static int hf_saprouter_route_offset; |
158 | | static int hf_saprouter_route; |
159 | | static int hf_saprouter_route_string; |
160 | | |
161 | | static int hf_saprouter_route_requested_in; |
162 | | static int hf_saprouter_route_accepted_in; |
163 | | |
164 | | /* Route strings */ |
165 | | static int hf_saprouter_route_string_hostname; |
166 | | static int hf_saprouter_route_string_service; |
167 | | static int hf_saprouter_route_string_password; |
168 | | |
169 | | |
170 | | /* Error Information/Control Messages */ |
171 | | static int hf_saprouter_opcode; |
172 | | static int hf_saprouter_return_code; |
173 | | static int hf_saprouter_unknown; |
174 | | |
175 | | /* Error Information Messages */ |
176 | | static int hf_saprouter_error_length; |
177 | | static int hf_saprouter_error_string; |
178 | | static int hf_saprouter_error_eyecatcher; |
179 | | static int hf_saprouter_error_counter; |
180 | | static int hf_saprouter_error_error; |
181 | | static int hf_saprouter_error_return_code; |
182 | | static int hf_saprouter_error_component; |
183 | | static int hf_saprouter_error_release; |
184 | | static int hf_saprouter_error_version; |
185 | | static int hf_saprouter_error_module; |
186 | | static int hf_saprouter_error_line; |
187 | | static int hf_saprouter_error_detail; |
188 | | static int hf_saprouter_error_time; |
189 | | static int hf_saprouter_error_system_call; |
190 | | static int hf_saprouter_error_errorno; |
191 | | static int hf_saprouter_error_errorno_text; |
192 | | static int hf_saprouter_error_error_count; |
193 | | static int hf_saprouter_error_location; |
194 | | static int hf_saprouter_error_unknown; /* TODO: Unknown fields */ |
195 | | |
196 | | /* Control Messages */ |
197 | | static int hf_saprouter_control_length; |
198 | | static int hf_saprouter_control_string; |
199 | | static int hf_saprouter_control_unknown; |
200 | | |
201 | | /* Admin Messages */ |
202 | | static int hf_saprouter_admin_command; |
203 | | static int hf_saprouter_admin_password; |
204 | | static int hf_saprouter_admin_client_count_short; |
205 | | static int hf_saprouter_admin_client_count_int; |
206 | | static int hf_saprouter_admin_client_ids; |
207 | | static int hf_saprouter_admin_client_id; |
208 | | static int hf_saprouter_admin_address_mask; |
209 | | |
210 | | static int ett_saprouter; |
211 | | |
212 | | /* Expert info */ |
213 | | static expert_field ei_saprouter_route_password_found; |
214 | | static expert_field ei_saprouter_route_invalid_length; |
215 | | static expert_field ei_saprouter_info_password_found; |
216 | | static expert_field ei_saprouter_invalid_client_ids; |
217 | | static expert_field ei_saprouter_control_invalid_length; |
218 | | |
219 | | /* Global port preference */ |
220 | | static range_t *global_saprouter_port_range; |
221 | | |
222 | | |
223 | | /* Global SNC dissection preference */ |
224 | | static bool global_saprouter_snc_dissection = true; |
225 | | |
226 | | /* Protocol handle */ |
227 | | static dissector_handle_t saprouter_handle; |
228 | | |
229 | | /* Session state information being tracked in a SAP Router conversation */ |
230 | | typedef struct saprouter_session_state { |
231 | | bool route_information; |
232 | | unsigned route_requested_in; |
233 | | bool route_accepted; |
234 | | unsigned route_accepted_in; |
235 | | bool route_snc_protected; |
236 | | char *src_hostname; /* Source hostname (first entry in the route string) */ |
237 | | uint32_t src_port; /* Source port number */ |
238 | | char *src_password; /* Source password XXX: Check if possible */ |
239 | | char *dest_hostname; /* Destination hostname (last entry in the route string) */ |
240 | | uint32_t dest_port; /* Destination port number */ |
241 | | char *dest_password; /* Destination password */ |
242 | | } saprouter_session_state; |
243 | | |
244 | | /* |
245 | | * |
246 | | */ |
247 | | void proto_reg_handoff_saprouter(void); |
248 | | void proto_register_saprouter(void); |
249 | | |
250 | | |
251 | | static uint32_t |
252 | 0 | dissect_serviceport(char *port){ |
253 | 0 | uint32_t portnumber = 0; |
254 | |
|
255 | 0 | if (g_ascii_isdigit(port[0])){ |
256 | 0 | portnumber = (uint32_t)strtoul(port, NULL, 10); |
257 | 0 | } else if ((strlen(port)>5) && g_str_has_prefix(port, "sapdp")){ |
258 | 0 | portnumber = 3200 + (uint32_t)strtoul(port+5, NULL, 10); |
259 | 0 | } else if ((strlen(port)>5) && g_str_has_prefix(port, "sapgw")){ |
260 | 0 | portnumber = 3300 + (uint32_t)strtoul(port+5, NULL, 10); |
261 | 0 | } else if ((strlen(port)>5) && g_str_has_prefix(port, "sapms")){ |
262 | 0 | portnumber = 3600 + (uint32_t)strtoul(port+5, NULL, 10); |
263 | 0 | } |
264 | 0 | return (portnumber); |
265 | 0 | } |
266 | | |
267 | | static bool |
268 | | saprouter_tvb_strsize_bounded(tvbuff_t *tvb, uint32_t offset, uint32_t *len) |
269 | 0 | { |
270 | 0 | unsigned nul_offset; |
271 | 0 | int remaining; |
272 | |
|
273 | 0 | remaining = tvb_captured_length_remaining(tvb, offset); |
274 | 0 | if (remaining <= 0) { |
275 | 0 | return false; |
276 | 0 | } |
277 | | |
278 | 0 | if (!tvb_find_uint8_length(tvb, offset, (unsigned)remaining, '\0', &nul_offset)) { |
279 | 0 | return false; |
280 | 0 | } |
281 | | |
282 | 0 | *len = nul_offset - offset + 1; |
283 | 0 | return true; |
284 | 0 | } |
285 | | |
286 | | static bool |
287 | | saprouter_type_matches(tvbuff_t *tvb, uint32_t offset, uint32_t eyecatcher_length, const char *type) |
288 | 0 | { |
289 | 0 | uint32_t type_length = (uint32_t)strlen(type); |
290 | |
|
291 | 0 | if (eyecatcher_length != type_length + 1) { |
292 | 0 | return false; |
293 | 0 | } |
294 | | |
295 | 0 | return tvb_strneql(tvb, offset, type, type_length) == 0 && |
296 | 0 | tvb_get_uint8(tvb, offset + type_length) == '\0'; |
297 | 0 | } |
298 | | |
299 | | static void |
300 | 0 | dissect_routestring(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset, saprouter_session_state *session_state){ |
301 | 0 | int hop = 1; |
302 | 0 | uint32_t len, route_offset, int_port = 0; |
303 | 0 | char *hostname = NULL, *port = NULL, *password = NULL; |
304 | 0 | proto_item *route_hop = NULL, *route_password = NULL; |
305 | 0 | proto_tree *route_hop_tree = NULL; |
306 | |
|
307 | 0 | while (tvb_offset_exists(tvb, offset)){ |
308 | 0 | route_offset = offset; hostname = port = password = NULL; |
309 | | |
310 | | /* Create the subtree for this route hop */ |
311 | 0 | route_hop = proto_tree_add_item(tree, hf_saprouter_route_string, tvb, offset, 0, ENC_NA); |
312 | 0 | route_hop_tree = proto_item_add_subtree(route_hop, ett_saprouter); |
313 | 0 | proto_item_append_text(route_hop, ", nro %d", hop); |
314 | | |
315 | | /* Dissect the hostname string */ |
316 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) { |
317 | 0 | break; |
318 | 0 | } |
319 | 0 | hostname = (char *)tvb_get_string_enc(wmem_file_scope(), tvb, offset, len - 1, ENC_ASCII); |
320 | 0 | proto_tree_add_item(route_hop_tree, hf_saprouter_route_string_hostname, tvb, offset, len, ENC_ASCII); |
321 | 0 | offset += len; |
322 | | |
323 | | /* Dissect the port string */ |
324 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) { |
325 | 0 | break; |
326 | 0 | } |
327 | 0 | port = (char *)tvb_get_string_enc(pinfo->pool, tvb, offset, len - 1, ENC_ASCII); |
328 | 0 | proto_tree_add_item(route_hop_tree, hf_saprouter_route_string_service, tvb, offset, len, ENC_ASCII); |
329 | 0 | offset += len; |
330 | | |
331 | | /* Dissect the password string */ |
332 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) { |
333 | 0 | break; |
334 | 0 | } |
335 | 0 | password = (char *)tvb_get_string_enc(wmem_file_scope(), tvb, offset, len - 1, ENC_ASCII); |
336 | 0 | route_password = proto_tree_add_item(route_hop_tree, hf_saprouter_route_string_password, tvb, offset, len, ENC_ASCII); |
337 | | |
338 | | /* If a password was found, add a expert warning in the security category */ |
339 | 0 | if (len > 1){ |
340 | 0 | expert_add_info(pinfo, route_password, &ei_saprouter_route_password_found); |
341 | | |
342 | | /* Add the password to the credential tap */ |
343 | 0 | tap_credential_t *auth = wmem_new0(pinfo->pool, tap_credential_t); |
344 | 0 | auth->num = pinfo->num; |
345 | 0 | auth->password_hf_id = hf_saprouter_route_string_password; |
346 | 0 | auth->proto = "SAP Router Route String password"; |
347 | 0 | auth->username = wmem_strdup(pinfo->pool, CREDENTIALS_PLACEHOLDER); |
348 | 0 | tap_queue_packet(credentials_tap, pinfo, auth); |
349 | 0 | } |
350 | 0 | offset += len; |
351 | | |
352 | | /* Adjust the size of the route hop item now that we know the size */ |
353 | 0 | proto_item_set_len(route_hop, offset - route_offset); |
354 | | |
355 | | /* Get the service port in numeric format */ |
356 | 0 | int_port = dissect_serviceport(port); |
357 | | |
358 | | /* Add the first hostname/port as source in the conversation state*/ |
359 | 0 | if ((hop==1) && !(pinfo->fd->visited)){ |
360 | 0 | session_state->src_hostname = hostname; |
361 | 0 | session_state->src_port = int_port; |
362 | 0 | session_state->src_password = password; |
363 | 0 | } |
364 | 0 | hop++; |
365 | 0 | } |
366 | |
|
367 | 0 | if (!(pinfo->fd->visited)) { |
368 | | /* Add the last hostname/port as destination */ |
369 | 0 | if (hop!=1){ |
370 | 0 | session_state->dest_hostname = hostname; |
371 | 0 | session_state->dest_port = int_port; |
372 | 0 | session_state->dest_password = password; |
373 | 0 | } |
374 | | /* Save the status of the conversation state */ |
375 | 0 | session_state->route_information = true; |
376 | 0 | session_state->route_accepted = false; |
377 | 0 | } |
378 | |
|
379 | 0 | } |
380 | | |
381 | | static void |
382 | | dissect_errorstring(tvbuff_t *tvb, proto_tree *tree, uint32_t offset) |
383 | 0 | { |
384 | 0 | uint32_t len; |
385 | |
|
386 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
387 | 0 | proto_tree_add_item(tree, hf_saprouter_error_eyecatcher, tvb, offset, len, ENC_ASCII); |
388 | 0 | offset += len; |
389 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
390 | 0 | proto_tree_add_item(tree, hf_saprouter_error_counter, tvb, offset, len, ENC_ASCII); |
391 | 0 | offset += len; |
392 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
393 | 0 | proto_tree_add_item(tree, hf_saprouter_error_error, tvb, offset, len, ENC_ASCII); |
394 | 0 | offset += len; |
395 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
396 | 0 | proto_tree_add_item(tree, hf_saprouter_error_return_code, tvb, offset, len, ENC_ASCII); |
397 | 0 | offset += len; |
398 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
399 | 0 | proto_tree_add_item(tree, hf_saprouter_error_component, tvb, offset, len, ENC_ASCII); |
400 | 0 | offset += len; |
401 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
402 | 0 | proto_tree_add_item(tree, hf_saprouter_error_release, tvb, offset, len, ENC_ASCII); |
403 | 0 | offset += len; |
404 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
405 | 0 | proto_tree_add_item(tree, hf_saprouter_error_version, tvb, offset, len, ENC_ASCII); |
406 | 0 | offset += len; |
407 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
408 | 0 | proto_tree_add_item(tree, hf_saprouter_error_module, tvb, offset, len, ENC_ASCII); |
409 | 0 | offset += len; |
410 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
411 | 0 | proto_tree_add_item(tree, hf_saprouter_error_line, tvb, offset, len, ENC_ASCII); |
412 | 0 | offset += len; |
413 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
414 | 0 | proto_tree_add_item(tree, hf_saprouter_error_detail, tvb, offset, len, ENC_ASCII); |
415 | 0 | offset += len; |
416 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
417 | 0 | proto_tree_add_item(tree, hf_saprouter_error_time, tvb, offset, len, ENC_ASCII); |
418 | 0 | offset += len; |
419 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
420 | 0 | proto_tree_add_item(tree, hf_saprouter_error_system_call, tvb, offset, len, ENC_ASCII); |
421 | 0 | offset += len; |
422 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
423 | 0 | proto_tree_add_item(tree, hf_saprouter_error_errorno, tvb, offset, len, ENC_ASCII); |
424 | 0 | offset += len; |
425 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
426 | 0 | proto_tree_add_item(tree, hf_saprouter_error_errorno_text, tvb, offset, len, ENC_ASCII); |
427 | 0 | offset += len; |
428 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
429 | 0 | proto_tree_add_item(tree, hf_saprouter_error_error_count, tvb, offset, len, ENC_ASCII); |
430 | 0 | offset += len; |
431 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
432 | 0 | proto_tree_add_item(tree, hf_saprouter_error_location, tvb, offset, len, ENC_ASCII); |
433 | 0 | offset += len; |
434 | |
|
435 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
436 | 0 | proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII); |
437 | 0 | offset += len; |
438 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
439 | 0 | proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII); |
440 | 0 | offset += len; |
441 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
442 | 0 | proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII); |
443 | 0 | offset += len; |
444 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
445 | 0 | proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII); |
446 | 0 | offset += len; |
447 | |
|
448 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return; |
449 | 0 | proto_tree_add_item(tree, hf_saprouter_error_eyecatcher, tvb, offset, len, ENC_ASCII); |
450 | 0 | } |
451 | | |
452 | | |
453 | | static tvbuff_t* |
454 | 0 | dissect_saprouter_snc_frame(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, uint32_t offset _U_){ |
455 | | |
456 | | /* Call the SNC dissector */ |
457 | 0 | if (global_saprouter_snc_dissection == true){ |
458 | 0 | return dissect_sapsnc_frame(tvb, pinfo, tree, offset); |
459 | 0 | } |
460 | | |
461 | 0 | return NULL; |
462 | 0 | } |
463 | | |
464 | | |
465 | | static int |
466 | | dissect_saprouter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
467 | 0 | { |
468 | 0 | tvbuff_t *next_tvb = NULL; |
469 | 0 | uint8_t opcode; |
470 | 0 | uint32_t offset = 0, eyecatcher_length = 0; |
471 | 0 | int remaining; |
472 | 0 | conversation_t *conversation = NULL; |
473 | 0 | saprouter_session_state *session_state = NULL; |
474 | 0 | proto_item *ti = NULL, *ri = NULL, *ei = NULL, *ci = NULL, *gi = NULL, *admin_password = NULL; |
475 | 0 | proto_tree *saprouter_tree = NULL, *route_tree = NULL, *text_tree = NULL, *clients_tree = NULL; |
476 | | |
477 | | /* Search for a conversation */ |
478 | 0 | conversation = find_or_create_conversation(pinfo); |
479 | 0 | session_state = (saprouter_session_state *)conversation_get_proto_data(conversation, proto_saprouter); |
480 | 0 | if (!session_state){ |
481 | 0 | session_state = wmem_new(wmem_file_scope(), saprouter_session_state); |
482 | 0 | if (session_state){ |
483 | 0 | session_state->route_information = false; |
484 | 0 | session_state->route_requested_in = 0; |
485 | 0 | session_state->route_accepted = false; |
486 | 0 | session_state->route_accepted_in = 0; |
487 | 0 | session_state->route_snc_protected = false; |
488 | 0 | session_state->src_hostname = NULL; |
489 | 0 | session_state->src_port = 0; |
490 | 0 | session_state->src_password = NULL; |
491 | 0 | session_state->dest_hostname = NULL; |
492 | 0 | session_state->dest_port = 0; |
493 | 0 | session_state->dest_password = NULL; |
494 | 0 | conversation_add_proto_data(conversation, proto_saprouter, session_state); |
495 | 0 | } else { |
496 | | /* Unable to establish a conversation, break dissection of the packet */ |
497 | 0 | return 0; |
498 | 0 | } |
499 | 0 | } |
500 | | |
501 | | /* Add the protocol to the column */ |
502 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "SAPROUTER"); |
503 | | |
504 | | /* Add the main SAP Router subtree */ |
505 | 0 | ti = proto_tree_add_item(tree, proto_saprouter, tvb, offset, -1, ENC_NA); |
506 | 0 | saprouter_tree = proto_item_add_subtree(ti, ett_saprouter); |
507 | | |
508 | | /* Get the 'eye catcher' length */ |
509 | 0 | if (!saprouter_tvb_strsize_bounded(tvb, offset, &eyecatcher_length)) { |
510 | 0 | remaining = tvb_reported_length_remaining(tvb, offset); |
511 | 0 | eyecatcher_length = remaining > 0 ? (uint32_t)remaining : 0; |
512 | 0 | } |
513 | | |
514 | | /* Niping message */ |
515 | 0 | if (tvb_reported_length_remaining(tvb, offset) >= 10 && tvb_strneql(tvb, offset, SAPROUTER_TYPE_NIPING_STRING, 10) == 0) { |
516 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Niping message"); |
517 | |
|
518 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, offset, 10, ENC_ASCII); |
519 | 0 | offset += 10; |
520 | 0 | proto_item_append_text(ti, ", Niping message"); |
521 | |
|
522 | 0 | if (tvb_reported_length_remaining(tvb, offset)) { |
523 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_niping_message, tvb, offset, -1, ENC_NA); |
524 | 0 | } |
525 | |
|
526 | 0 | } |
527 | | /* Admin Message Type */ |
528 | 0 | else if (saprouter_type_matches(tvb, offset, eyecatcher_length, SAPROUTER_TYPE_ADMIN_STRING)) { |
529 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Admin message"); |
530 | |
|
531 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, offset, eyecatcher_length, ENC_ASCII); |
532 | 0 | offset += eyecatcher_length; |
533 | 0 | proto_item_append_text(ti, ", Admin message"); |
534 | |
|
535 | 0 | if (tvb_reported_length_remaining(tvb, offset) < 2) { |
536 | 0 | expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_control_invalid_length, "SAP Router admin message is shorter than 2 fixed bytes"); |
537 | 0 | return tvb_reported_length(tvb); |
538 | 0 | } |
539 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_ni_version, tvb, offset, 1, ENC_BIG_ENDIAN); |
540 | 0 | offset++; |
541 | |
|
542 | 0 | opcode = tvb_get_uint8(tvb, offset); |
543 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_admin_command, tvb, offset, 1, ENC_BIG_ENDIAN); |
544 | 0 | offset++; |
545 | |
|
546 | 0 | switch (opcode){ |
547 | 0 | case 2:{ /* Info request */ |
548 | 0 | uint32_t password_len; |
549 | |
|
550 | 0 | if (tvb_reported_length_remaining(tvb, offset) < 2) { |
551 | 0 | expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_control_invalid_length, "SAP Router admin info request is shorter than 2 fixed bytes"); |
552 | 0 | return tvb_reported_length(tvb); |
553 | 0 | } |
554 | 0 | offset+=2; /* Skip 2 bytes */ |
555 | | /* Check if a password was supplied */ |
556 | 0 | if (saprouter_tvb_strsize_bounded(tvb, offset, &password_len) && password_len > 1){ |
557 | 0 | admin_password = proto_tree_add_item(saprouter_tree, hf_saprouter_admin_password, tvb, offset, password_len, ENC_ASCII); |
558 | 0 | expert_add_info(pinfo, admin_password, &ei_saprouter_info_password_found); |
559 | | |
560 | | /* Add the password to the credential tap */ |
561 | 0 | tap_credential_t *auth = wmem_new0(pinfo->pool, tap_credential_t); |
562 | 0 | auth->num = pinfo->num; |
563 | 0 | auth->password_hf_id = hf_saprouter_admin_password; |
564 | 0 | auth->proto = "SAP Router Info Request password"; |
565 | 0 | auth->username = wmem_strdup(pinfo->pool, CREDENTIALS_PLACEHOLDER); |
566 | 0 | tap_queue_packet(credentials_tap, pinfo, auth); |
567 | 0 | } |
568 | 0 | break; |
569 | 0 | } |
570 | 0 | case 10: /* Set Peer Trace */ |
571 | 0 | case 11:{ /* Clear Peer Trace */ |
572 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_admin_address_mask, tvb, offset, 32, ENC_ASCII); |
573 | 0 | break; |
574 | 0 | } |
575 | 0 | case 6: /* Cancel Route request */ |
576 | 0 | case 12: /* Trace Connection */ |
577 | 0 | case 13: /* Trace Connection */ |
578 | 0 | { |
579 | 0 | uint32_t client_count = 0, client_count_actual = 0; |
580 | | |
581 | | /* Retrieve the client count first */ |
582 | 0 | if (opcode == 6){ |
583 | 0 | if (tvb_reported_length_remaining(tvb, offset) < 4) { |
584 | 0 | expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_control_invalid_length, "SAP Router cancel route request is shorter than 4 fixed bytes"); |
585 | 0 | return tvb_reported_length(tvb); |
586 | 0 | } |
587 | 0 | offset+=2; /* Skip 2 bytes for Cancel Route request*/ |
588 | 0 | client_count = tvb_get_ntohs(tvb, offset); |
589 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_admin_client_count_short, tvb, offset, 2, ENC_BIG_ENDIAN); |
590 | 0 | offset+=2; |
591 | 0 | } else { |
592 | 0 | if (tvb_reported_length_remaining(tvb, offset) < 4) { |
593 | 0 | expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_control_invalid_length, "SAP Router trace connection request is shorter than 4 fixed bytes"); |
594 | 0 | return tvb_reported_length(tvb); |
595 | 0 | } |
596 | 0 | client_count = tvb_get_ntohl(tvb, offset); |
597 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_admin_client_count_int, tvb, offset, 4, ENC_BIG_ENDIAN); |
598 | 0 | offset+=4; |
599 | 0 | } |
600 | | |
601 | | /* Parse the list of client IDs */ |
602 | 0 | remaining = tvb_reported_length_remaining(tvb, offset); |
603 | 0 | ci = proto_tree_add_item(saprouter_tree, hf_saprouter_admin_client_ids, tvb, offset, remaining > 0 ? remaining : 0, ENC_NA); |
604 | 0 | clients_tree = proto_item_add_subtree(ci, ett_saprouter); |
605 | 0 | while (tvb_offset_exists(tvb, offset) && tvb_reported_length_remaining(tvb, offset)>=4){ |
606 | 0 | proto_tree_add_item(clients_tree, hf_saprouter_admin_client_id, tvb, offset, 4, ENC_BIG_ENDIAN); |
607 | 0 | offset+=4; |
608 | 0 | client_count_actual+=1; |
609 | 0 | } |
610 | | |
611 | | /* Check if the actual count of IDs differes from the reported number */ |
612 | 0 | if ((client_count_actual != client_count) || tvb_reported_length_remaining(tvb, offset)>0){ |
613 | 0 | expert_add_info(pinfo, clients_tree, &ei_saprouter_invalid_client_ids); |
614 | 0 | } |
615 | |
|
616 | 0 | break; |
617 | 0 | } |
618 | 0 | default: { |
619 | | /* Skip 2 bytes */ |
620 | 0 | break; |
621 | 0 | } |
622 | 0 | } |
623 | | |
624 | | /* Route Message Type */ |
625 | 0 | } else if (saprouter_type_matches(tvb, offset, eyecatcher_length, SAPROUTER_TYPE_ROUTE_STRING)){ |
626 | 0 | uint32_t route_length = 0, route_offset = 0; |
627 | 0 | tvbuff_t *route_tvb = NULL; |
628 | |
|
629 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Route message"); |
630 | |
|
631 | 0 | if (tvb_reported_length_remaining(tvb, offset) < SAPROUTER_ROUTE_OFFSET_OFFSET + 4) { |
632 | 0 | expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_route_invalid_length, "Route message is shorter than %u bytes", SAPROUTER_ROUTE_OFFSET_OFFSET + 4); |
633 | 0 | return tvb_reported_length(tvb); |
634 | 0 | } |
635 | | |
636 | | /* Get the route length/offset */ |
637 | 0 | route_length = tvb_get_ntohl(tvb, offset + SAPROUTER_ROUTE_LENGTH_OFFSET); |
638 | 0 | route_offset = offset + SAPROUTER_ROUTE_OFFSET_OFFSET + 4; |
639 | |
|
640 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, 0, eyecatcher_length, ENC_ASCII); |
641 | 0 | offset += eyecatcher_length; |
642 | 0 | proto_item_append_text(ti, ", Route message"); |
643 | | /* Add the fields */ |
644 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_route_version, tvb, offset, 1, ENC_BIG_ENDIAN); |
645 | 0 | offset++; |
646 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_ni_version, tvb, offset, 1, ENC_BIG_ENDIAN); |
647 | 0 | offset++; |
648 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_entries, tvb, offset, 1, ENC_BIG_ENDIAN); |
649 | 0 | offset++; |
650 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_talk_mode, tvb, offset, 1, ENC_BIG_ENDIAN); |
651 | 0 | offset+=3; /* There're two unused bytes there */ |
652 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_rest_nodes, tvb, offset, 1, ENC_BIG_ENDIAN); |
653 | 0 | offset++; |
654 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_route_length, tvb, offset, 4, ENC_BIG_ENDIAN); |
655 | 0 | offset+=4; |
656 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_route_offset, tvb, offset, 4, ENC_BIG_ENDIAN); |
657 | 0 | offset+=4; |
658 | | /* Add the route tree */ |
659 | 0 | remaining = tvb_reported_length_remaining(tvb, route_offset); |
660 | 0 | if (route_offset < offset || remaining < 0) { |
661 | 0 | expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_route_invalid_length, "Route string offset is invalid (route_offset=%u)", route_offset); |
662 | 0 | route_length = 0; |
663 | 0 | } else if ((uint32_t)remaining != route_length){ |
664 | 0 | expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_route_invalid_length, "Route string length is invalid (remaining=%d, route_length=%d)", remaining, route_length); |
665 | 0 | route_length = (uint32_t)remaining; |
666 | 0 | } |
667 | 0 | ri = proto_tree_add_item(saprouter_tree, hf_saprouter_route, tvb, route_offset, route_length, ENC_NA); |
668 | 0 | route_tree = proto_item_add_subtree(ri, ett_saprouter); |
669 | | |
670 | | /* Dissect the route string */ |
671 | 0 | if (route_length > 0) { |
672 | 0 | route_tvb = tvb_new_subset_length(tvb, route_offset, route_length); |
673 | 0 | dissect_routestring(route_tvb, pinfo, route_tree, 0, session_state); |
674 | 0 | } |
675 | | |
676 | | /* If this is the first time we're seeing this packet, mark it as the one where the route was requested */ |
677 | 0 | if (!pinfo->fd->visited) { |
678 | 0 | session_state->route_requested_in = pinfo->num; |
679 | 0 | } |
680 | | |
681 | | /* Add the route to the colinfo*/ |
682 | 0 | if (session_state->src_hostname){ |
683 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", Source: Hostname=%s Service Port=%d", session_state->src_hostname, session_state->src_port); |
684 | 0 | if (session_state->src_password && strlen(session_state->src_password)>0) |
685 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " Password=%s", session_state->src_password); |
686 | 0 | } |
687 | 0 | if (session_state->dest_hostname){ |
688 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", Destination: Hostname=%s Service Port=%d", session_state->dest_hostname, session_state->dest_port); |
689 | 0 | if (session_state->dest_password && strlen(session_state->dest_password)>0) |
690 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " Password=%s", session_state->dest_password); |
691 | 0 | } |
692 | |
|
693 | 0 | if (session_state->route_accepted && session_state->route_accepted_in) { |
694 | 0 | gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_accepted_in, tvb, 0, 0, session_state->route_accepted_in); |
695 | 0 | proto_item_set_generated(gi); |
696 | 0 | } |
697 | | |
698 | | /* Error Information/Control Message Type */ |
699 | 0 | } else if (saprouter_type_matches(tvb, offset, eyecatcher_length, SAPROUTER_TYPE_ERR_STRING)){ |
700 | | |
701 | | /* Extract the opcode if possible to determine the type of message */ |
702 | 0 | if (tvb_offset_exists(tvb, offset + 10)) { |
703 | 0 | opcode = tvb_get_uint8(tvb, offset + 10); |
704 | 0 | } else { |
705 | 0 | opcode = 0; |
706 | 0 | } |
707 | |
|
708 | 0 | col_set_str(pinfo->cinfo, COL_INFO, (opcode==0)? "Error information" : "Control message"); |
709 | |
|
710 | 0 | uint32_t text_length = 0; |
711 | |
|
712 | 0 | proto_item_append_text(ti, (opcode==0)? ", Error information" : ", Control message"); |
713 | 0 | remaining = tvb_reported_length_remaining(tvb, offset); |
714 | 0 | if (remaining < (int)(eyecatcher_length + SAPROUTER_ERR_FIXED_LEN)) { |
715 | 0 | expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_control_invalid_length, "SAP Router error/control message is shorter than %u fixed bytes", eyecatcher_length + SAPROUTER_ERR_FIXED_LEN); |
716 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, offset, eyecatcher_length, ENC_ASCII); |
717 | 0 | return tvb_reported_length(tvb); |
718 | 0 | } |
719 | | /* Add the fields */ |
720 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, offset, eyecatcher_length, ENC_ASCII); |
721 | 0 | offset += eyecatcher_length; |
722 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_ni_version, tvb, offset, 1, ENC_BIG_ENDIAN); |
723 | 0 | offset++; |
724 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_opcode, tvb, offset, 1, ENC_BIG_ENDIAN); |
725 | 0 | offset+=2; /* There's a unused byte there */ |
726 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_return_code, tvb, offset, 4, ENC_BIG_ENDIAN); |
727 | 0 | offset+=4; |
728 | |
|
729 | 0 | text_length = tvb_get_ntohl(tvb, offset); |
730 | | /* Error Information Message */ |
731 | 0 | if (opcode == 0){ |
732 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_error_length, tvb, offset, 4, ENC_BIG_ENDIAN); |
733 | 0 | offset+=4; |
734 | 0 | remaining = tvb_reported_length_remaining(tvb, offset); |
735 | 0 | if ((text_length > 0) && remaining > 0){ |
736 | 0 | if ((uint32_t)remaining < text_length) { |
737 | 0 | expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_control_invalid_length, "SAP Router error text is shorter than its reported length (remaining=%d, text_length=%u)", remaining, text_length); |
738 | 0 | text_length = (uint32_t)remaining; |
739 | 0 | } |
740 | | /* Add the error string tree */ |
741 | 0 | ei = proto_tree_add_item(saprouter_tree, hf_saprouter_error_string, tvb, offset, text_length, ENC_NA); |
742 | 0 | text_tree = proto_item_add_subtree(ei, ett_saprouter); |
743 | 0 | dissect_errorstring(tvb_new_subset_length(tvb, offset, text_length), text_tree, 0); |
744 | 0 | offset += text_length; |
745 | 0 | } |
746 | | |
747 | | /* Add an unknown int field */ |
748 | 0 | if (tvb_reported_length_remaining(tvb, offset) >= 4) { |
749 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_unknown, tvb, offset, 4, ENC_BIG_ENDIAN); |
750 | 0 | } |
751 | | |
752 | | /* Control Message */ |
753 | 0 | } else { |
754 | | /* Add the opcode name */ |
755 | 0 | proto_item_append_text(ti, ", opcode=%s", val_to_str_const(opcode, saprouter_opcode_vals, "Unknown")); |
756 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", opcode=%s", val_to_str_const(opcode, saprouter_opcode_vals, "Unknown")); |
757 | |
|
758 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_control_length, tvb, offset, 4, ENC_BIG_ENDIAN); |
759 | 0 | offset+=4; |
760 | 0 | remaining = tvb_reported_length_remaining(tvb, offset); |
761 | 0 | if ((text_length > 0) && remaining > 0){ |
762 | 0 | if ((uint32_t)remaining < text_length) { |
763 | 0 | expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_control_invalid_length, "SAP Router control text is shorter than its reported length (remaining=%d, text_length=%u)", remaining, text_length); |
764 | 0 | text_length = (uint32_t)remaining; |
765 | 0 | } |
766 | | /* Add the control string tree */ |
767 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_control_string, tvb, offset, text_length, ENC_ASCII); |
768 | 0 | offset += text_length; |
769 | 0 | } |
770 | | |
771 | | /* SNC request, mark the conversation as SNC protected and dissect the SNC frame */ |
772 | 0 | if (opcode == 70 || opcode == 71){ |
773 | 0 | session_state->route_snc_protected = true; |
774 | 0 | if (tvb_reported_length_remaining(tvb, offset) > 0) { |
775 | 0 | dissect_saprouter_snc_frame(tvb, pinfo, tree, offset); |
776 | 0 | } |
777 | | |
778 | | /* Other opcodes */ |
779 | 0 | } else { |
780 | 0 | if (tvb_reported_length_remaining(tvb, offset) >= 4) { |
781 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_control_unknown, tvb, offset, 4, ENC_ASCII); |
782 | 0 | } |
783 | 0 | } |
784 | |
|
785 | 0 | } |
786 | | |
787 | | /* Route Acceptance (NI_PONG) Message Type */ |
788 | 0 | } else if (tvb_strneql(tvb, offset, SAPROUTER_TYPE_ROUTE_ACCEPT, eyecatcher_length) == 0){ |
789 | | /* Route information available */ |
790 | 0 | if (session_state->route_information){ |
791 | | /* If this is the first time we're seen the packet, mark is as the one where the route was accepted */ |
792 | 0 | if (!pinfo->fd->visited) { |
793 | 0 | session_state->route_accepted = true; |
794 | 0 | session_state->route_accepted_in = pinfo->num; |
795 | 0 | } |
796 | |
|
797 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", from %s:%d to %s:%d", session_state->src_hostname, session_state->src_port, session_state->dest_hostname, session_state->dest_port); |
798 | 0 | proto_item_append_text(ti, ", from %s:%d to %s:%d", session_state->src_hostname, session_state->src_port, session_state->dest_hostname, session_state->dest_port); |
799 | |
|
800 | 0 | if (session_state->route_requested_in) { |
801 | 0 | gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_requested_in, tvb, 0, 0, session_state->route_requested_in); |
802 | 0 | proto_item_set_generated(gi); |
803 | 0 | } |
804 | 0 | } |
805 | | |
806 | | /* Unknown Message Type */ |
807 | 0 | } else { |
808 | |
|
809 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Routed message"); |
810 | 0 | proto_item_append_text(ti, ", Routed message"); |
811 | | |
812 | | /* If the session is protected with SNC, first dissect the SNC frame |
813 | | * and save the content for further dissection. |
814 | | */ |
815 | 0 | if (session_state->route_snc_protected) { |
816 | 0 | col_append_str(pinfo->cinfo, COL_INFO, ", SNC protected"); |
817 | 0 | proto_item_append_text(ti, ", SNC protected"); |
818 | 0 | next_tvb = dissect_saprouter_snc_frame(tvb, pinfo, tree, offset); |
819 | | |
820 | | /* If the session is not protected dissect the entire payload */ |
821 | 0 | } else { |
822 | 0 | next_tvb = tvb; |
823 | 0 | } |
824 | | |
825 | | /* If the session has information about the route requested */ |
826 | 0 | if (session_state->route_information){ |
827 | | |
828 | | /* Route accepted */ |
829 | 0 | if (session_state->route_accepted){ |
830 | |
|
831 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", from %s:%d to %s:%d ", session_state->src_hostname, session_state->src_port, session_state->dest_hostname, session_state->dest_port); |
832 | 0 | proto_item_append_text(ti, ", from %s:%d to %s:%d ", session_state->src_hostname, session_state->src_port, session_state->dest_hostname, session_state->dest_port); |
833 | |
|
834 | 0 | if (session_state->route_requested_in) { |
835 | 0 | gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_requested_in, tvb, 0, 0, session_state->route_requested_in); |
836 | 0 | proto_item_set_generated(gi); |
837 | 0 | } |
838 | 0 | if (session_state->route_accepted_in) { |
839 | 0 | gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_accepted_in, tvb, 0, 0, session_state->route_accepted_in); |
840 | 0 | proto_item_set_generated(gi); |
841 | 0 | } |
842 | | |
843 | | /* Route not accepted but some information available */ |
844 | 0 | } else { |
845 | 0 | col_append_str(pinfo->cinfo, COL_INFO, ", to unknown destination"); |
846 | 0 | proto_item_append_text(ti, ", to unknown destination"); |
847 | 0 | } |
848 | | |
849 | | /* Call the dissector in the NI protocol sub-dissectors table |
850 | | * according to the route destination port number. */ |
851 | 0 | if (next_tvb) { |
852 | 0 | dissect_sap_protocol_payload(next_tvb, offset, pinfo, tree, 0, session_state->dest_port); |
853 | 0 | } |
854 | |
|
855 | 0 | } else { |
856 | | /* No route information available */ |
857 | 0 | col_append_str(pinfo->cinfo, COL_INFO, ", to unknown destination"); |
858 | 0 | proto_item_append_text(ti, ", to unknown destination"); |
859 | 0 | } |
860 | 0 | } |
861 | | |
862 | 0 | return tvb_reported_length(tvb); |
863 | 0 | } |
864 | | |
865 | | void |
866 | | proto_register_saprouter(void) |
867 | 16 | { |
868 | 16 | static hf_register_info hf[] = { |
869 | 16 | { &hf_saprouter_type, |
870 | 16 | { "Type", "saprouter.type", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
871 | | |
872 | | /* Niping message */ |
873 | 16 | { &hf_saprouter_niping_message, |
874 | 16 | { "Niping message", "saprouter.message", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
875 | | |
876 | | /* NI Route messages */ |
877 | 16 | { &hf_saprouter_route_version, |
878 | 16 | { "Route version", "saprouter.version", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
879 | 16 | { &hf_saprouter_ni_version, |
880 | 16 | { "NI version", "saprouter.niversion", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
881 | 16 | { &hf_saprouter_entries, |
882 | 16 | { "Entries", "saprouter.entries", FT_UINT8, BASE_DEC, NULL, 0x0, "Total number of entries", HFILL }}, |
883 | 16 | { &hf_saprouter_talk_mode, |
884 | 16 | { "Talk Mode", "saprouter.talkmode", FT_UINT8, BASE_DEC, VALS(saprouter_talk_mode_vals), 0x0, NULL, HFILL }}, |
885 | 16 | { &hf_saprouter_rest_nodes, |
886 | 16 | { "Remaining Hops", "saprouter.restnodes", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
887 | 16 | { &hf_saprouter_route_length, |
888 | 16 | { "Route String Length", "saprouter.routelength", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
889 | 16 | { &hf_saprouter_route_offset, |
890 | 16 | { "Route String Offset", "saprouter.routeoffset", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
891 | 16 | { &hf_saprouter_route, |
892 | 16 | { "Route String", "saprouter.routestring", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
893 | 16 | { &hf_saprouter_route_string, |
894 | 16 | { "Route Hop", "saprouter.routestring", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
895 | 16 | { &hf_saprouter_route_string_hostname, |
896 | 16 | { "Hostname", "saprouter.routestring.hostname", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
897 | 16 | { &hf_saprouter_route_string_service, |
898 | 16 | { "Service", "saprouter.routestring.service", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
899 | 16 | { &hf_saprouter_route_string_password, |
900 | 16 | { "Password", "saprouter.routestring.password", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
901 | | |
902 | 16 | { &hf_saprouter_route_requested_in, |
903 | 16 | { "Route Requested in", "saprouter.requested_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "The route request for this packet is in this packet", HFILL }}, |
904 | 16 | { &hf_saprouter_route_accepted_in, |
905 | 16 | { "Route Accepted in", "saprouter.accepted_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "The route for this packet was accepted in this packet", HFILL }}, |
906 | | |
907 | | /* NI error information / Control messages */ |
908 | 16 | { &hf_saprouter_opcode, |
909 | 16 | { "Operation Code", "saprouter.opcode", FT_UINT8, BASE_DEC, VALS(saprouter_opcode_vals), 0x0, NULL, HFILL }}, |
910 | 16 | { &hf_saprouter_return_code, |
911 | 16 | { "Return Code", "saprouter.returncode", FT_INT32, BASE_DEC, VALS(saprouter_return_code_vals), 0x0, NULL, HFILL }}, |
912 | 16 | { &hf_saprouter_unknown, |
913 | 16 | { "Unknown field", "saprouter.unknown", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
914 | | |
915 | | /* NI Error Information messages */ |
916 | 16 | { &hf_saprouter_error_length, |
917 | 16 | { "Error Information Text Length", "saprouter.errorlength", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
918 | 16 | { &hf_saprouter_error_string, |
919 | 16 | { "Error Information Text", "saprouter.errortext", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
920 | 16 | { &hf_saprouter_error_eyecatcher, |
921 | 16 | { "Eyecatcher", "saprouter.errortext.eyecatcher", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
922 | 16 | { &hf_saprouter_error_counter, |
923 | 16 | { "Counter", "saprouter.errortext.counter", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
924 | 16 | { &hf_saprouter_error_error, |
925 | 16 | { "Error", "saprouter.errortext.error", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
926 | 16 | { &hf_saprouter_error_return_code, |
927 | 16 | { "Return code", "saprouter.errortext.returncode", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
928 | 16 | { &hf_saprouter_error_component, |
929 | 16 | { "Component", "saprouter.errortext.component", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
930 | 16 | { &hf_saprouter_error_release, |
931 | 16 | { "Release", "saprouter.errortext.release", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
932 | 16 | { &hf_saprouter_error_version, |
933 | 16 | { "Version", "saprouter.errortext.version", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
934 | 16 | { &hf_saprouter_error_module, |
935 | 16 | { "Module", "saprouter.errortext.module", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
936 | 16 | { &hf_saprouter_error_line, |
937 | 16 | { "Line", "saprouter.errortext.line", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
938 | 16 | { &hf_saprouter_error_detail, |
939 | 16 | { "Detail", "saprouter.errortext.detail", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
940 | 16 | { &hf_saprouter_error_time, |
941 | 16 | { "Time", "saprouter.errortext.time", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
942 | 16 | { &hf_saprouter_error_system_call, |
943 | 16 | { "System Call", "saprouter.errortext.system_call", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
944 | 16 | { &hf_saprouter_error_errorno, |
945 | 16 | { "Error Number", "saprouter.errortext.errorno", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
946 | 16 | { &hf_saprouter_error_errorno_text, |
947 | 16 | { "Error Number Text", "saprouter.errortext.errorno_text", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
948 | 16 | { &hf_saprouter_error_location, |
949 | 16 | { "Location", "saprouter.errortext.location", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
950 | 16 | { &hf_saprouter_error_error_count, |
951 | 16 | { "Error Count", "saprouter.errortext.error_count", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
952 | 16 | { &hf_saprouter_error_unknown, |
953 | 16 | { "Unknown field", "saprouter.errortext.unknown", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
954 | | |
955 | | /* Control messages */ |
956 | 16 | { &hf_saprouter_control_length, |
957 | 16 | { "Control Text Length", "saprouter.controllength", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
958 | 16 | { &hf_saprouter_control_string, |
959 | 16 | { "Control Text", "saprouter.controltext", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
960 | 16 | { &hf_saprouter_control_unknown, |
961 | 16 | { "Control Unknown field", "saprouter.controlunknown", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
962 | | |
963 | | /* Router Admin messages */ |
964 | 16 | { &hf_saprouter_admin_command, |
965 | 16 | { "Admin Command", "saprouter.command", FT_UINT8, BASE_DEC, VALS(saprouter_admin_command_vals), 0x0, NULL, HFILL }}, |
966 | 16 | { &hf_saprouter_admin_password, |
967 | 16 | { "Admin Command Info Password", "saprouter.password", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
968 | 16 | { &hf_saprouter_admin_client_count_short, |
969 | 16 | { "Admin Command Client Count", "saprouter.client_count", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
970 | 16 | { &hf_saprouter_admin_client_count_int, |
971 | 16 | { "Admin Command Client Count", "saprouter.client_count", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
972 | 16 | { &hf_saprouter_admin_client_ids, |
973 | 16 | { "Admin Command Client IDs", "saprouter.client_ids", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
974 | 16 | { &hf_saprouter_admin_client_id, |
975 | 16 | { "Admin Command Client ID", "saprouter.client_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
976 | 16 | { &hf_saprouter_admin_address_mask, |
977 | 16 | { "Admin Command Address Mask", "saprouter.address_mask", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
978 | 16 | }; |
979 | | |
980 | | /* Setup protocol subtree array */ |
981 | 16 | static int *ett[] = { |
982 | 16 | &ett_saprouter |
983 | 16 | }; |
984 | | |
985 | | /* Register the expert info */ |
986 | 16 | static ei_register_info ei[] = { |
987 | 16 | { &ei_saprouter_route_password_found, { "saprouter.routestring.password.found", PI_SECURITY, PI_WARN, "Route password found", EXPFILL }}, |
988 | 16 | { &ei_saprouter_info_password_found, { "saprouter.password.found", PI_SECURITY, PI_WARN, "Info password found", EXPFILL }}, |
989 | 16 | { &ei_saprouter_route_invalid_length, { "saprouter.routestring.routelength.invalid", PI_MALFORMED, PI_WARN, "The route string length is invalid", EXPFILL }}, |
990 | 16 | { &ei_saprouter_invalid_client_ids, { "saprouter.client_ids.invalid", PI_MALFORMED, PI_WARN, "Client IDs list is malformed", EXPFILL }}, |
991 | 16 | { &ei_saprouter_control_invalid_length, { "saprouter.control.length.invalid", PI_MALFORMED, PI_WARN, "The error/control message length is invalid", EXPFILL }}, |
992 | 16 | }; |
993 | | |
994 | 16 | module_t *saprouter_module; |
995 | 16 | expert_module_t* saprouter_expert; |
996 | | |
997 | | /* Register the protocol */ |
998 | 16 | proto_saprouter = proto_register_protocol("SAP Router Protocol", "SAPROUTER", "saprouter"); |
999 | | |
1000 | 16 | proto_register_field_array(proto_saprouter, hf, array_length(hf)); |
1001 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
1002 | | |
1003 | 16 | saprouter_expert = expert_register_protocol(proto_saprouter); |
1004 | 16 | expert_register_field_array(saprouter_expert, ei, array_length(ei)); |
1005 | | |
1006 | 16 | register_dissector("saprouter", dissect_saprouter, proto_saprouter); |
1007 | | |
1008 | | /* Register the preferences */ |
1009 | 16 | saprouter_module = prefs_register_protocol(proto_saprouter, proto_reg_handoff_saprouter); |
1010 | | |
1011 | 16 | range_convert_str(wmem_epan_scope(), &global_saprouter_port_range, SAPROUTER_PORT_RANGE, MAX_TCP_PORT); |
1012 | 16 | prefs_register_range_preference(saprouter_module, "tcp_ports", "SAP Router Protocol TCP port numbers", "Port numbers used for SAP Router Protocol (default " SAPROUTER_PORT_RANGE ")", &global_saprouter_port_range, MAX_TCP_PORT); |
1013 | | |
1014 | 16 | prefs_register_bool_preference(saprouter_module, "snc_dissection", "Dissect SAP SNC frames", "Whether the SAP Router Protocol dissector should call the SAP SNC dissector for SNC frames", &global_saprouter_snc_dissection); |
1015 | | |
1016 | | /* Register the tap*/ |
1017 | 16 | credentials_tap = register_tap("credentials"); |
1018 | | |
1019 | 16 | } |
1020 | | |
1021 | | |
1022 | | /** |
1023 | | * Helpers for dealing with the port range |
1024 | | */ |
1025 | | static void range_delete_callback (uint32_t port, void *ptr _U_) |
1026 | 0 | { |
1027 | 0 | dissector_delete_uint("sapni.port", port, saprouter_handle); |
1028 | 0 | } |
1029 | | |
1030 | | static void range_add_callback (uint32_t port, void *ptr _U_) |
1031 | 32 | { |
1032 | 32 | dissector_add_uint("sapni.port", port, saprouter_handle); |
1033 | 32 | } |
1034 | | |
1035 | | |
1036 | | /** |
1037 | | * Register Hand off for the SAP Router Protocol |
1038 | | */ |
1039 | | void |
1040 | | proto_reg_handoff_saprouter(void) |
1041 | 16 | { |
1042 | 16 | static bool initialized = false; |
1043 | 16 | static range_t *saprouter_port_range; |
1044 | | |
1045 | 16 | if (!initialized) { |
1046 | 16 | saprouter_handle = create_dissector_handle(dissect_saprouter, proto_saprouter); |
1047 | 16 | initialized = true; |
1048 | 16 | } else { |
1049 | 0 | range_foreach(saprouter_port_range, range_delete_callback, NULL); |
1050 | 0 | wmem_free(wmem_epan_scope(), saprouter_port_range); |
1051 | 0 | } |
1052 | | |
1053 | 16 | saprouter_port_range = range_copy(wmem_epan_scope(), global_saprouter_port_range); |
1054 | 16 | range_foreach(saprouter_port_range, range_add_callback, NULL); |
1055 | | |
1056 | 16 | } |
1057 | | |
1058 | | /* |
1059 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
1060 | | * |
1061 | | * Local variables: |
1062 | | * c-basic-offset: 8 |
1063 | | * tab-width: 8 |
1064 | | * indent-tabs-mode: t |
1065 | | * End: |
1066 | | * |
1067 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
1068 | | * :indentSize=8:tabSize=8:noTabs=false: |
1069 | | */ |