/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 | | |
28 | | #include <epan/tap.h> |
29 | | #include <ui/tap-credentials.h> |
30 | | |
31 | | #include "packet-sapni.h" |
32 | | #include "packet-sapsnc.h" |
33 | | |
34 | | |
35 | | /* Define default ports */ |
36 | 14 | #define SAPROUTER_PORT_RANGE "3298-3299" |
37 | | |
38 | | /* |
39 | | * Length of the frame header |
40 | | */ |
41 | | #define SAPROUTER_HEADER_LEN 8 |
42 | | |
43 | | /* |
44 | | * Offsets of header fields |
45 | | */ |
46 | 0 | #define SAPROUTER_ROUTE_LENGTH_OFFSET 16 |
47 | 0 | #define SAPROUTER_ROUTE_OFFSET_OFFSET 20 |
48 | | |
49 | | /* SAP Router Eye Catcher strings */ |
50 | 0 | #define SAPROUTER_TYPE_NIPING_STRING "EYECATCHER" |
51 | 0 | #define SAPROUTER_TYPE_ROUTE_STRING "NI_ROUTE" |
52 | 0 | #define SAPROUTER_TYPE_ROUTE_ACCEPT "NI_PONG" |
53 | 0 | #define SAPROUTER_TYPE_ERR_STRING "NI_RTERR" |
54 | 0 | #define SAPROUTER_TYPE_ADMIN_STRING "ROUTER_ADM" |
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 | | |
218 | | /* Global port preference */ |
219 | | static range_t *global_saprouter_port_range; |
220 | | |
221 | | |
222 | | /* Global SNC dissection preference */ |
223 | | static bool global_saprouter_snc_dissection = true; |
224 | | |
225 | | /* Protocol handle */ |
226 | | static dissector_handle_t saprouter_handle; |
227 | | |
228 | | /* Session state information being tracked in a SAP Router conversation */ |
229 | | typedef struct saprouter_session_state { |
230 | | bool route_information; |
231 | | unsigned route_requested_in; |
232 | | bool route_accepted; |
233 | | unsigned route_accepted_in; |
234 | | bool route_snc_protected; |
235 | | char *src_hostname; /* Source hostname (first entry in the route string) */ |
236 | | uint32_t src_port; /* Source port number */ |
237 | | char *src_password; /* Source password XXX: Check if possible */ |
238 | | char *dest_hostname; /* Destination hostname (last entry in the route string) */ |
239 | | uint32_t dest_port; /* Destination port number */ |
240 | | char *dest_password; /* Destination password */ |
241 | | } saprouter_session_state; |
242 | | |
243 | | /* |
244 | | * |
245 | | */ |
246 | | void proto_reg_handoff_saprouter(void); |
247 | | void proto_register_saprouter(void); |
248 | | |
249 | | |
250 | | static uint32_t |
251 | 0 | dissect_serviceport(char *port){ |
252 | 0 | uint32_t portnumber = 0; |
253 | |
|
254 | 0 | if (g_ascii_isdigit(port[0])){ |
255 | 0 | portnumber = (uint32_t)strtoul(port, NULL, 10); |
256 | 0 | } else if ((strlen(port)>5) && g_str_has_prefix(port, "sapdp")){ |
257 | 0 | portnumber = 3200 + (uint32_t)strtoul(port+5, NULL, 10); |
258 | 0 | } else if ((strlen(port)>5) && g_str_has_prefix(port, "sapgw")){ |
259 | 0 | portnumber = 3300 + (uint32_t)strtoul(port+5, NULL, 10); |
260 | 0 | } else if ((strlen(port)>5) && g_str_has_prefix(port, "sapms")){ |
261 | 0 | portnumber = 3600 + (uint32_t)strtoul(port+5, NULL, 10); |
262 | 0 | } |
263 | 0 | return (portnumber); |
264 | 0 | } |
265 | | |
266 | | static void |
267 | 0 | dissect_routestring(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset, saprouter_session_state *session_state){ |
268 | 0 | int hop = 1; |
269 | 0 | uint32_t len, route_offset, int_port = 0; |
270 | 0 | char *hostname = NULL, *port = NULL, *password = NULL; |
271 | 0 | proto_item *route_hop = NULL, *route_password = NULL; |
272 | 0 | proto_tree *route_hop_tree = NULL; |
273 | |
|
274 | 0 | while (tvb_offset_exists(tvb, offset)){ |
275 | 0 | route_offset = offset; hostname = port = password = NULL; |
276 | | |
277 | | /* Create the subtree for this route hop */ |
278 | 0 | route_hop = proto_tree_add_item(tree, hf_saprouter_route_string, tvb, offset, 0, ENC_NA); |
279 | 0 | route_hop_tree = proto_item_add_subtree(route_hop, ett_saprouter); |
280 | 0 | proto_item_append_text(route_hop, ", nro %d", hop); |
281 | | |
282 | | /* Dissect the hostname string */ |
283 | 0 | len = tvb_strsize(tvb, offset); |
284 | 0 | hostname = (char *)tvb_get_string_enc(wmem_file_scope(), tvb, offset, len - 1, ENC_ASCII); |
285 | 0 | proto_tree_add_item(route_hop_tree, hf_saprouter_route_string_hostname, tvb, offset, len, ENC_ASCII); |
286 | 0 | offset += len; |
287 | | |
288 | | /* Dissect the port string */ |
289 | 0 | len = tvb_strsize(tvb, offset); |
290 | 0 | port = (char *)tvb_get_string_enc(pinfo->pool, tvb, offset, len - 1, ENC_ASCII); |
291 | 0 | proto_tree_add_item(route_hop_tree, hf_saprouter_route_string_service, tvb, offset, len, ENC_ASCII); |
292 | 0 | offset += len; |
293 | | |
294 | | /* Dissect the password string */ |
295 | 0 | len = tvb_strsize(tvb, offset); |
296 | 0 | password = (char *)tvb_get_string_enc(wmem_file_scope(), tvb, offset, len - 1, ENC_ASCII); |
297 | 0 | route_password = proto_tree_add_item(route_hop_tree, hf_saprouter_route_string_password, tvb, offset, len, ENC_ASCII); |
298 | | |
299 | | /* If a password was found, add a expert warning in the security category */ |
300 | 0 | if (len > 1){ |
301 | 0 | expert_add_info(pinfo, route_password, &ei_saprouter_route_password_found); |
302 | | |
303 | | /* Add the password to the credential tap */ |
304 | 0 | tap_credential_t *auth = wmem_new0(pinfo->pool, tap_credential_t); |
305 | 0 | auth->num = pinfo->num; |
306 | 0 | auth->password_hf_id = hf_saprouter_route_string_password; |
307 | 0 | auth->proto = "SAP Router Route String password"; |
308 | 0 | auth->username = wmem_strdup(pinfo->pool, TAP_CREDENTIALS_PLACEHOLDER); |
309 | 0 | tap_queue_packet(credentials_tap, pinfo, auth); |
310 | 0 | } |
311 | 0 | offset += len; |
312 | | |
313 | | /* Adjust the size of the route hop item now that we know the size */ |
314 | 0 | proto_item_set_len(route_hop, offset - route_offset); |
315 | | |
316 | | /* Get the service port in numeric format */ |
317 | 0 | int_port = dissect_serviceport(port); |
318 | | |
319 | | /* Add the first hostname/port as source in the conversation state*/ |
320 | 0 | if ((hop==1) && !(pinfo->fd->visited)){ |
321 | 0 | session_state->src_hostname = hostname; |
322 | 0 | session_state->src_port = int_port; |
323 | 0 | session_state->src_password = password; |
324 | 0 | } |
325 | 0 | hop++; |
326 | 0 | } |
327 | |
|
328 | 0 | if (!(pinfo->fd->visited)) { |
329 | | /* Add the last hostname/port as destination */ |
330 | 0 | if (hop!=1){ |
331 | 0 | session_state->dest_hostname = hostname; |
332 | 0 | session_state->dest_port = int_port; |
333 | 0 | session_state->dest_password = password; |
334 | 0 | } |
335 | | /* Save the status of the conversation state */ |
336 | 0 | session_state->route_information = true; |
337 | 0 | session_state->route_accepted = false; |
338 | 0 | } |
339 | |
|
340 | 0 | } |
341 | | |
342 | | static void |
343 | | dissect_errorstring(tvbuff_t *tvb, proto_tree *tree, uint32_t offset) |
344 | 0 | { |
345 | 0 | uint32_t len; |
346 | |
|
347 | 0 | len = tvb_strsize(tvb, offset); |
348 | 0 | proto_tree_add_item(tree, hf_saprouter_error_eyecatcher, tvb, offset, len, ENC_ASCII); |
349 | 0 | offset += len; |
350 | 0 | len = tvb_strsize(tvb, offset); |
351 | 0 | proto_tree_add_item(tree, hf_saprouter_error_counter, tvb, offset, len, ENC_ASCII); |
352 | 0 | offset += len; |
353 | 0 | len = tvb_strsize(tvb, offset); |
354 | 0 | proto_tree_add_item(tree, hf_saprouter_error_error, tvb, offset, len, ENC_ASCII); |
355 | 0 | offset += len; |
356 | 0 | len = tvb_strsize(tvb, offset); |
357 | 0 | proto_tree_add_item(tree, hf_saprouter_error_return_code, tvb, offset, len, ENC_ASCII); |
358 | 0 | offset += len; |
359 | 0 | len = tvb_strsize(tvb, offset); |
360 | 0 | proto_tree_add_item(tree, hf_saprouter_error_component, tvb, offset, len, ENC_ASCII); |
361 | 0 | offset += len; |
362 | 0 | len = tvb_strsize(tvb, offset); |
363 | 0 | proto_tree_add_item(tree, hf_saprouter_error_release, tvb, offset, len, ENC_ASCII); |
364 | 0 | offset += len; |
365 | 0 | len = tvb_strsize(tvb, offset); |
366 | 0 | proto_tree_add_item(tree, hf_saprouter_error_version, tvb, offset, len, ENC_ASCII); |
367 | 0 | offset += len; |
368 | 0 | len = tvb_strsize(tvb, offset); |
369 | 0 | proto_tree_add_item(tree, hf_saprouter_error_module, tvb, offset, len, ENC_ASCII); |
370 | 0 | offset += len; |
371 | 0 | len = tvb_strsize(tvb, offset); |
372 | 0 | proto_tree_add_item(tree, hf_saprouter_error_line, tvb, offset, len, ENC_ASCII); |
373 | 0 | offset += len; |
374 | 0 | len = tvb_strsize(tvb, offset); |
375 | 0 | proto_tree_add_item(tree, hf_saprouter_error_detail, tvb, offset, len, ENC_ASCII); |
376 | 0 | offset += len; |
377 | 0 | len = tvb_strsize(tvb, offset); |
378 | 0 | proto_tree_add_item(tree, hf_saprouter_error_time, tvb, offset, len, ENC_ASCII); |
379 | 0 | offset += len; |
380 | 0 | len = tvb_strsize(tvb, offset); |
381 | 0 | proto_tree_add_item(tree, hf_saprouter_error_system_call, tvb, offset, len, ENC_ASCII); |
382 | 0 | offset += len; |
383 | 0 | len = tvb_strsize(tvb, offset); |
384 | 0 | proto_tree_add_item(tree, hf_saprouter_error_errorno, tvb, offset, len, ENC_ASCII); |
385 | 0 | offset += len; |
386 | 0 | len = tvb_strsize(tvb, offset); |
387 | 0 | proto_tree_add_item(tree, hf_saprouter_error_errorno_text, tvb, offset, len, ENC_ASCII); |
388 | 0 | offset += len; |
389 | 0 | len = tvb_strsize(tvb, offset); |
390 | 0 | proto_tree_add_item(tree, hf_saprouter_error_error_count, tvb, offset, len, ENC_ASCII); |
391 | 0 | offset += len; |
392 | 0 | len = tvb_strsize(tvb, offset); |
393 | 0 | proto_tree_add_item(tree, hf_saprouter_error_location, tvb, offset, len, ENC_ASCII); |
394 | 0 | offset += len; |
395 | |
|
396 | 0 | len = tvb_strsize(tvb, offset); |
397 | 0 | proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII); |
398 | 0 | offset += len; |
399 | 0 | len = tvb_strsize(tvb, offset); |
400 | 0 | proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII); |
401 | 0 | offset += len; |
402 | 0 | len = tvb_strsize(tvb, offset); |
403 | 0 | proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII); |
404 | 0 | offset += len; |
405 | 0 | len = tvb_strsize(tvb, offset); |
406 | 0 | proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII); |
407 | 0 | offset += len; |
408 | |
|
409 | 0 | len = tvb_strsize(tvb, offset); |
410 | 0 | proto_tree_add_item(tree, hf_saprouter_error_eyecatcher, tvb, offset, len, ENC_ASCII); |
411 | 0 | } |
412 | | |
413 | | |
414 | | static tvbuff_t* |
415 | 0 | dissect_saprouter_snc_frame(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, uint32_t offset _U_){ |
416 | | |
417 | | /* Call the SNC dissector */ |
418 | 0 | if (global_saprouter_snc_dissection == true){ |
419 | 0 | return dissect_sapsnc_frame(tvb, pinfo, tree, offset); |
420 | 0 | } |
421 | | |
422 | 0 | return NULL; |
423 | 0 | } |
424 | | |
425 | | |
426 | | static int |
427 | | dissect_saprouter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
428 | 0 | { |
429 | 0 | tvbuff_t *next_tvb = NULL; |
430 | 0 | uint8_t opcode; |
431 | 0 | uint32_t offset = 0, eyecatcher_length = 0; |
432 | 0 | conversation_t *conversation = NULL; |
433 | 0 | saprouter_session_state *session_state = NULL; |
434 | 0 | proto_item *ti = NULL, *ri = NULL, *ei = NULL, *ci = NULL, *gi = NULL, *admin_password = NULL; |
435 | 0 | proto_tree *saprouter_tree = NULL, *route_tree = NULL, *text_tree = NULL, *clients_tree = NULL; |
436 | | |
437 | | /* Search for a conversation */ |
438 | 0 | conversation = find_or_create_conversation(pinfo); |
439 | 0 | session_state = (saprouter_session_state *)conversation_get_proto_data(conversation, proto_saprouter); |
440 | 0 | if (!session_state){ |
441 | 0 | session_state = wmem_new(wmem_file_scope(), saprouter_session_state); |
442 | 0 | if (session_state){ |
443 | 0 | session_state->route_information = false; |
444 | 0 | session_state->route_requested_in = 0; |
445 | 0 | session_state->route_accepted = false; |
446 | 0 | session_state->route_accepted_in = 0; |
447 | 0 | session_state->route_snc_protected = false; |
448 | 0 | session_state->src_hostname = NULL; |
449 | 0 | session_state->src_port = 0; |
450 | 0 | session_state->src_password = NULL; |
451 | 0 | session_state->dest_hostname = NULL; |
452 | 0 | session_state->dest_port = 0; |
453 | 0 | session_state->dest_password = NULL; |
454 | 0 | conversation_add_proto_data(conversation, proto_saprouter, session_state); |
455 | 0 | } else { |
456 | | /* Unable to establish a conversation, break dissection of the packet */ |
457 | 0 | return 0; |
458 | 0 | } |
459 | 0 | } |
460 | | |
461 | | /* Add the protocol to the column */ |
462 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "SAPROUTER"); |
463 | | |
464 | | /* Add the main SAP Router subtree */ |
465 | 0 | ti = proto_tree_add_item(tree, proto_saprouter, tvb, offset, -1, ENC_NA); |
466 | 0 | saprouter_tree = proto_item_add_subtree(ti, ett_saprouter); |
467 | | |
468 | | /* Get the 'eye catcher' length */ |
469 | 0 | eyecatcher_length = tvb_strsize(tvb, offset); |
470 | | |
471 | | /* Niping message */ |
472 | 0 | if (tvb_reported_length_remaining(tvb, offset) >= 10 && tvb_strneql(tvb, offset, SAPROUTER_TYPE_NIPING_STRING, 10) == 0) { |
473 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Niping message"); |
474 | |
|
475 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, offset, 10, ENC_ASCII); |
476 | 0 | offset += 10; |
477 | 0 | proto_item_append_text(ti, ", Niping message"); |
478 | |
|
479 | 0 | if (tvb_reported_length_remaining(tvb, offset)) { |
480 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_niping_message, tvb, offset, -1, ENC_NA); |
481 | 0 | } |
482 | |
|
483 | 0 | } |
484 | | /* Admin Message Type */ |
485 | 0 | else if (tvb_strneql(tvb, offset, SAPROUTER_TYPE_ADMIN_STRING, eyecatcher_length) == 0) { |
486 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Admin message"); |
487 | |
|
488 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, offset, eyecatcher_length, ENC_ASCII); |
489 | 0 | offset += eyecatcher_length; |
490 | 0 | proto_item_append_text(ti, ", Admin message"); |
491 | |
|
492 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_ni_version, tvb, offset, 1, ENC_BIG_ENDIAN); |
493 | 0 | offset++; |
494 | |
|
495 | 0 | opcode = tvb_get_uint8(tvb, offset); |
496 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_admin_command, tvb, offset, 1, ENC_BIG_ENDIAN); |
497 | 0 | offset++; |
498 | |
|
499 | 0 | switch (opcode){ |
500 | 0 | case 2:{ /* Info request */ |
501 | 0 | offset+=2; /* Skip 2 bytes */ |
502 | | /* Check if a password was supplied */ |
503 | 0 | if (tvb_offset_exists(tvb, offset) && (tvb_strsize(tvb, offset) > 0)){ |
504 | 0 | admin_password = proto_tree_add_item(saprouter_tree, hf_saprouter_admin_password, tvb, offset, tvb_strsize(tvb, offset), ENC_ASCII); |
505 | 0 | expert_add_info(pinfo, admin_password, &ei_saprouter_info_password_found); |
506 | | |
507 | | /* Add the password to the credential tap */ |
508 | 0 | tap_credential_t *auth = wmem_new0(pinfo->pool, tap_credential_t); |
509 | 0 | auth->num = pinfo->num; |
510 | 0 | auth->password_hf_id = hf_saprouter_admin_password; |
511 | 0 | auth->proto = "SAP Router Info Request password"; |
512 | 0 | auth->username = wmem_strdup(pinfo->pool, TAP_CREDENTIALS_PLACEHOLDER); |
513 | 0 | tap_queue_packet(credentials_tap, pinfo, auth); |
514 | 0 | } |
515 | 0 | break; |
516 | 0 | } |
517 | 0 | case 10: /* Set Peer Trace */ |
518 | 0 | case 11:{ /* Clear Peer Trace */ |
519 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_admin_address_mask, tvb, offset, 32, ENC_ASCII); |
520 | 0 | break; |
521 | 0 | } |
522 | 0 | case 6: /* Cancel Route request */ |
523 | 0 | case 12: /* Trace Connection */ |
524 | 0 | case 13: /* Trace Connection */ |
525 | 0 | { |
526 | 0 | uint16_t client_count = 0, client_count_actual = 0; |
527 | | |
528 | | /* Retrieve the client count first */ |
529 | 0 | if (opcode == 6){ |
530 | 0 | offset+=2; /* Skip 2 bytes for Cancel Route request*/ |
531 | 0 | client_count = tvb_get_ntohs(tvb, offset); |
532 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_admin_client_count_short, tvb, offset, 2, ENC_BIG_ENDIAN); |
533 | 0 | offset+=2; |
534 | 0 | } else { |
535 | 0 | client_count = tvb_get_ntohl(tvb, offset); |
536 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_admin_client_count_int, tvb, offset, 4, ENC_BIG_ENDIAN); |
537 | 0 | offset+=4; |
538 | 0 | } |
539 | | |
540 | | /* Parse the list of client IDs */ |
541 | 0 | ci = proto_tree_add_item(saprouter_tree, hf_saprouter_admin_client_ids, tvb, offset, 4*client_count, ENC_NA); |
542 | 0 | clients_tree = proto_item_add_subtree(ci, ett_saprouter); |
543 | 0 | while (tvb_offset_exists(tvb, offset) && tvb_reported_length_remaining(tvb, offset)>=4){ |
544 | 0 | proto_tree_add_item(clients_tree, hf_saprouter_admin_client_id, tvb, offset, 4, ENC_BIG_ENDIAN); |
545 | 0 | offset+=4; |
546 | 0 | client_count_actual+=1; |
547 | 0 | } |
548 | | |
549 | | /* Check if the actual count of IDs differes from the reported number */ |
550 | 0 | if ((client_count_actual != client_count) || tvb_reported_length_remaining(tvb, offset)>0){ |
551 | 0 | expert_add_info(pinfo, clients_tree, &ei_saprouter_invalid_client_ids); |
552 | 0 | } |
553 | |
|
554 | 0 | break; |
555 | 0 | } |
556 | 0 | default: { |
557 | | /* Skip 2 bytes */ |
558 | 0 | break; |
559 | 0 | } |
560 | 0 | } |
561 | | |
562 | | /* Route Message Type */ |
563 | 0 | } else if (tvb_strneql(tvb, offset, SAPROUTER_TYPE_ROUTE_STRING, eyecatcher_length) == 0){ |
564 | 0 | uint32_t route_length = 0, route_offset = 0; |
565 | |
|
566 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Route message"); |
567 | | |
568 | | /* Get the route length/offset */ |
569 | 0 | route_length = tvb_get_ntohl(tvb, offset + SAPROUTER_ROUTE_LENGTH_OFFSET); |
570 | 0 | route_offset = offset + SAPROUTER_ROUTE_OFFSET_OFFSET + 4; |
571 | |
|
572 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, 0, eyecatcher_length, ENC_ASCII); |
573 | 0 | offset += eyecatcher_length; |
574 | 0 | proto_item_append_text(ti, ", Route message"); |
575 | | /* Add the fields */ |
576 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_route_version, tvb, offset, 1, ENC_BIG_ENDIAN); |
577 | 0 | offset++; |
578 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_ni_version, tvb, offset, 1, ENC_BIG_ENDIAN); |
579 | 0 | offset++; |
580 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_entries, tvb, offset, 1, ENC_BIG_ENDIAN); |
581 | 0 | offset++; |
582 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_talk_mode, tvb, offset, 1, ENC_BIG_ENDIAN); |
583 | 0 | offset+=3; /* There're two unused bytes there */ |
584 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_rest_nodes, tvb, offset, 1, ENC_BIG_ENDIAN); |
585 | 0 | offset++; |
586 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_route_length, tvb, offset, 4, ENC_BIG_ENDIAN); |
587 | 0 | offset+=4; |
588 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_route_offset, tvb, offset, 4, ENC_BIG_ENDIAN); |
589 | 0 | offset+=4; |
590 | | /* Add the route tree */ |
591 | 0 | if ((uint32_t)tvb_reported_length_remaining(tvb, offset) != route_length){ |
592 | 0 | expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_route_invalid_length, "Route string length is invalid (remaining=%d, route_length=%d)", tvb_reported_length_remaining(tvb, offset), route_length); |
593 | 0 | route_length = (uint32_t)tvb_reported_length_remaining(tvb, offset); |
594 | 0 | } |
595 | 0 | ri = proto_tree_add_item(saprouter_tree, hf_saprouter_route, tvb, offset, route_length, ENC_NA); |
596 | 0 | route_tree = proto_item_add_subtree(ri, ett_saprouter); |
597 | | |
598 | | /* Dissect the route string */ |
599 | 0 | dissect_routestring(tvb, pinfo, route_tree, route_offset, session_state); |
600 | | |
601 | | /* If this is the first time we're seeing this packet, mark it as the one where the route was requested */ |
602 | 0 | if (!pinfo->fd->visited) { |
603 | 0 | session_state->route_requested_in = pinfo->num; |
604 | 0 | } |
605 | | |
606 | | /* Add the route to the colinfo*/ |
607 | 0 | if (session_state->src_hostname){ |
608 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", Source: Hostname=%s Service Port=%d", session_state->src_hostname, session_state->src_port); |
609 | 0 | if (strlen(session_state->src_password)>0) |
610 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " Password=%s", session_state->src_password); |
611 | 0 | } |
612 | 0 | if (session_state->dest_hostname){ |
613 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", Destination: Hostname=%s Service Port=%d", session_state->dest_hostname, session_state->dest_port); |
614 | 0 | if (strlen(session_state->dest_password)>0) |
615 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, " Password=%s", session_state->dest_password); |
616 | 0 | } |
617 | |
|
618 | 0 | if (session_state->route_accepted && session_state->route_accepted_in) { |
619 | 0 | gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_accepted_in, tvb, 0, 0, session_state->route_accepted_in); |
620 | 0 | proto_item_set_generated(gi); |
621 | 0 | } |
622 | | |
623 | | /* Error Information/Control Message Type */ |
624 | 0 | } else if (tvb_strneql(tvb, offset, SAPROUTER_TYPE_ERR_STRING, eyecatcher_length) == 0){ |
625 | | |
626 | | /* Extract the opcode if possible to determine the type of message */ |
627 | 0 | if (tvb_offset_exists(tvb, offset + 10)) { |
628 | 0 | opcode = tvb_get_uint8(tvb, offset + 10); |
629 | 0 | } else { |
630 | 0 | opcode = 0; |
631 | 0 | } |
632 | |
|
633 | 0 | col_set_str(pinfo->cinfo, COL_INFO, (opcode==0)? "Error information" : "Control message"); |
634 | |
|
635 | 0 | uint32_t text_length = 0; |
636 | |
|
637 | 0 | proto_item_append_text(ti, (opcode==0)? ", Error information" : ", Control message"); |
638 | | /* Add the fields */ |
639 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, offset, eyecatcher_length, ENC_ASCII); |
640 | 0 | offset += eyecatcher_length; |
641 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_ni_version, tvb, offset, 1, ENC_BIG_ENDIAN); |
642 | 0 | offset++; |
643 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_opcode, tvb, offset, 1, ENC_BIG_ENDIAN); |
644 | 0 | offset+=2; /* There's a unused byte there */ |
645 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_return_code, tvb, offset, 4, ENC_BIG_ENDIAN); |
646 | 0 | offset+=4; |
647 | |
|
648 | 0 | text_length = tvb_get_ntohl(tvb, offset); |
649 | | /* Error Information Message */ |
650 | 0 | if (opcode == 0){ |
651 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_error_length, tvb, offset, 4, ENC_BIG_ENDIAN); |
652 | 0 | offset+=4; |
653 | 0 | if ((text_length > 0) && tvb_offset_exists(tvb, offset+text_length)){ |
654 | | /* Add the error string tree */ |
655 | 0 | ei = proto_tree_add_item(saprouter_tree, hf_saprouter_error_string, tvb, offset, text_length, ENC_NA); |
656 | 0 | text_tree = proto_item_add_subtree(ei, ett_saprouter); |
657 | 0 | dissect_errorstring(tvb, text_tree, offset); |
658 | 0 | offset += text_length; |
659 | 0 | } |
660 | | |
661 | | /* Add an unknown int field */ |
662 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_unknown, tvb, offset, 4, ENC_BIG_ENDIAN); |
663 | | |
664 | | /* Control Message */ |
665 | 0 | } else { |
666 | | /* Add the opcode name */ |
667 | 0 | proto_item_append_text(ti, ", opcode=%s", val_to_str_const(opcode, saprouter_opcode_vals, "Unknown")); |
668 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", opcode=%s", val_to_str_const(opcode, saprouter_opcode_vals, "Unknown")); |
669 | |
|
670 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_control_length, tvb, offset, 4, ENC_BIG_ENDIAN); |
671 | 0 | offset+=4; |
672 | 0 | if ((text_length >0) && tvb_offset_exists(tvb, offset+text_length)){ |
673 | | /* Add the control string tree */ |
674 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_control_string, tvb, offset, text_length, ENC_ASCII); |
675 | 0 | offset += text_length; |
676 | 0 | } |
677 | | |
678 | | /* SNC request, mark the conversation as SNC protected and dissect the SNC frame */ |
679 | 0 | if (opcode == 70 || opcode == 71){ |
680 | 0 | session_state->route_snc_protected = true; |
681 | 0 | dissect_saprouter_snc_frame(tvb, pinfo, tree, offset); |
682 | | |
683 | | /* Other opcodes */ |
684 | 0 | } else { |
685 | 0 | proto_tree_add_item(saprouter_tree, hf_saprouter_control_unknown, tvb, offset, 4, ENC_ASCII); |
686 | 0 | } |
687 | |
|
688 | 0 | } |
689 | | |
690 | | /* Route Acceptance (NI_PONG) Message Type */ |
691 | 0 | } else if (tvb_strneql(tvb, offset, SAPROUTER_TYPE_ROUTE_ACCEPT, eyecatcher_length) == 0){ |
692 | | /* Route information available */ |
693 | 0 | if (session_state->route_information){ |
694 | | /* If this is the first time we're seen the packet, mark is as the one where the route was accepted */ |
695 | 0 | if (!pinfo->fd->visited) { |
696 | 0 | session_state->route_accepted = true; |
697 | 0 | session_state->route_accepted_in = pinfo->num; |
698 | 0 | } |
699 | |
|
700 | 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); |
701 | 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); |
702 | |
|
703 | 0 | if (session_state->route_requested_in) { |
704 | 0 | gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_requested_in, tvb, 0, 0, session_state->route_requested_in); |
705 | 0 | proto_item_set_generated(gi); |
706 | 0 | } |
707 | 0 | } |
708 | | |
709 | | /* Unknown Message Type */ |
710 | 0 | } else { |
711 | |
|
712 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Routed message"); |
713 | 0 | proto_item_append_text(ti, ", Routed message"); |
714 | | |
715 | | /* If the session is protected with SNC, first dissect the SNC frame |
716 | | * and save the content for further dissection. |
717 | | */ |
718 | 0 | if (session_state->route_snc_protected) { |
719 | 0 | col_append_str(pinfo->cinfo, COL_INFO, ", SNC protected"); |
720 | 0 | proto_item_append_text(ti, ", SNC protected"); |
721 | 0 | next_tvb = dissect_saprouter_snc_frame(tvb, pinfo, tree, offset); |
722 | | |
723 | | /* If the session is not protected dissect the entire payload */ |
724 | 0 | } else { |
725 | 0 | next_tvb = tvb; |
726 | 0 | } |
727 | | |
728 | | /* If the session has information about the route requested */ |
729 | 0 | if (session_state->route_information){ |
730 | | |
731 | | /* Route accepted */ |
732 | 0 | if (session_state->route_accepted){ |
733 | |
|
734 | 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); |
735 | 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); |
736 | |
|
737 | 0 | if (session_state->route_requested_in) { |
738 | 0 | gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_requested_in, tvb, 0, 0, session_state->route_requested_in); |
739 | 0 | proto_item_set_generated(gi); |
740 | 0 | } |
741 | 0 | if (session_state->route_accepted_in) { |
742 | 0 | gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_accepted_in, tvb, 0, 0, session_state->route_accepted_in); |
743 | 0 | proto_item_set_generated(gi); |
744 | 0 | } |
745 | | |
746 | | /* Route not accepted but some information available */ |
747 | 0 | } else { |
748 | 0 | col_append_str(pinfo->cinfo, COL_INFO, ", to unknown destination"); |
749 | 0 | proto_item_append_text(ti, ", to unknown destination"); |
750 | 0 | } |
751 | | |
752 | | /* Call the dissector in the NI protocol sub-dissectors table |
753 | | * according to the route destination port number. */ |
754 | 0 | if (next_tvb) { |
755 | 0 | dissect_sap_protocol_payload(next_tvb, offset, pinfo, tree, 0, session_state->dest_port); |
756 | 0 | } |
757 | |
|
758 | 0 | } else { |
759 | | /* No route information available */ |
760 | 0 | col_append_str(pinfo->cinfo, COL_INFO, ", to unknown destination"); |
761 | 0 | proto_item_append_text(ti, ", to unknown destination"); |
762 | 0 | } |
763 | 0 | } |
764 | | |
765 | 0 | return tvb_reported_length(tvb); |
766 | 0 | } |
767 | | |
768 | | void |
769 | | proto_register_saprouter(void) |
770 | 14 | { |
771 | 14 | static hf_register_info hf[] = { |
772 | 14 | { &hf_saprouter_type, |
773 | 14 | { "Type", "saprouter.type", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
774 | | |
775 | | /* Niping message */ |
776 | 14 | { &hf_saprouter_niping_message, |
777 | 14 | { "Niping message", "saprouter.message", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
778 | | |
779 | | /* NI Route messages */ |
780 | 14 | { &hf_saprouter_route_version, |
781 | 14 | { "Route version", "saprouter.version", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
782 | 14 | { &hf_saprouter_ni_version, |
783 | 14 | { "NI version", "saprouter.niversion", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
784 | 14 | { &hf_saprouter_entries, |
785 | 14 | { "Entries", "saprouter.entries", FT_UINT8, BASE_DEC, NULL, 0x0, "Total number of entries", HFILL }}, |
786 | 14 | { &hf_saprouter_talk_mode, |
787 | 14 | { "Talk Mode", "saprouter.talkmode", FT_UINT8, BASE_DEC, VALS(saprouter_talk_mode_vals), 0x0, NULL, HFILL }}, |
788 | 14 | { &hf_saprouter_rest_nodes, |
789 | 14 | { "Remaining Hops", "saprouter.restnodes", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
790 | 14 | { &hf_saprouter_route_length, |
791 | 14 | { "Route String Length", "saprouter.routelength", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
792 | 14 | { &hf_saprouter_route_offset, |
793 | 14 | { "Route String Offset", "saprouter.routeoffset", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
794 | 14 | { &hf_saprouter_route, |
795 | 14 | { "Route String", "saprouter.routestring", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
796 | 14 | { &hf_saprouter_route_string, |
797 | 14 | { "Route Hop", "saprouter.routestring", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
798 | 14 | { &hf_saprouter_route_string_hostname, |
799 | 14 | { "Hostname", "saprouter.routestring.hostname", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
800 | 14 | { &hf_saprouter_route_string_service, |
801 | 14 | { "Service", "saprouter.routestring.service", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
802 | 14 | { &hf_saprouter_route_string_password, |
803 | 14 | { "Password", "saprouter.routestring.password", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
804 | | |
805 | 14 | { &hf_saprouter_route_requested_in, |
806 | 14 | { "Route Requested in", "saprouter.requested_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "The route request for this packet is in this packet", HFILL }}, |
807 | 14 | { &hf_saprouter_route_accepted_in, |
808 | 14 | { "Route Accepted in", "saprouter.accepted_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "The route for this packet was accepted in this packet", HFILL }}, |
809 | | |
810 | | /* NI error information / Control messages */ |
811 | 14 | { &hf_saprouter_opcode, |
812 | 14 | { "Operation Code", "saprouter.opcode", FT_UINT8, BASE_DEC, VALS(saprouter_opcode_vals), 0x0, NULL, HFILL }}, |
813 | 14 | { &hf_saprouter_return_code, |
814 | 14 | { "Return Code", "saprouter.returncode", FT_INT32, BASE_DEC, VALS(saprouter_return_code_vals), 0x0, NULL, HFILL }}, |
815 | 14 | { &hf_saprouter_unknown, |
816 | 14 | { "Unknown field", "saprouter.unknown", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
817 | | |
818 | | /* NI Error Information messages */ |
819 | 14 | { &hf_saprouter_error_length, |
820 | 14 | { "Error Information Text Length", "saprouter.errorlength", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
821 | 14 | { &hf_saprouter_error_string, |
822 | 14 | { "Error Information Text", "saprouter.errortext", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
823 | 14 | { &hf_saprouter_error_eyecatcher, |
824 | 14 | { "Eyecatcher", "saprouter.errortext.eyecatcher", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
825 | 14 | { &hf_saprouter_error_counter, |
826 | 14 | { "Counter", "saprouter.errortext.counter", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
827 | 14 | { &hf_saprouter_error_error, |
828 | 14 | { "Error", "saprouter.errortext.error", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
829 | 14 | { &hf_saprouter_error_return_code, |
830 | 14 | { "Return code", "saprouter.errortext.returncode", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
831 | 14 | { &hf_saprouter_error_component, |
832 | 14 | { "Component", "saprouter.errortext.component", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
833 | 14 | { &hf_saprouter_error_release, |
834 | 14 | { "Release", "saprouter.errortext.release", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
835 | 14 | { &hf_saprouter_error_version, |
836 | 14 | { "Version", "saprouter.errortext.version", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
837 | 14 | { &hf_saprouter_error_module, |
838 | 14 | { "Module", "saprouter.errortext.module", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
839 | 14 | { &hf_saprouter_error_line, |
840 | 14 | { "Line", "saprouter.errortext.line", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
841 | 14 | { &hf_saprouter_error_detail, |
842 | 14 | { "Detail", "saprouter.errortext.detail", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
843 | 14 | { &hf_saprouter_error_time, |
844 | 14 | { "Time", "saprouter.errortext.time", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
845 | 14 | { &hf_saprouter_error_system_call, |
846 | 14 | { "System Call", "saprouter.errortext.system_call", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
847 | 14 | { &hf_saprouter_error_errorno, |
848 | 14 | { "Error Number", "saprouter.errortext.errorno", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
849 | 14 | { &hf_saprouter_error_errorno_text, |
850 | 14 | { "Error Number Text", "saprouter.errortext.errorno_text", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
851 | 14 | { &hf_saprouter_error_location, |
852 | 14 | { "Location", "saprouter.errortext.location", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
853 | 14 | { &hf_saprouter_error_error_count, |
854 | 14 | { "Error Count", "saprouter.errortext.error_count", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
855 | 14 | { &hf_saprouter_error_unknown, |
856 | 14 | { "Unknown field", "saprouter.errortext.unknown", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
857 | | |
858 | | /* Control messages */ |
859 | 14 | { &hf_saprouter_control_length, |
860 | 14 | { "Control Text Length", "saprouter.controllength", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
861 | 14 | { &hf_saprouter_control_string, |
862 | 14 | { "Control Text", "saprouter.controltext", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
863 | 14 | { &hf_saprouter_control_unknown, |
864 | 14 | { "Control Unknown field", "saprouter.controlunknown", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
865 | | |
866 | | /* Router Admin messages */ |
867 | 14 | { &hf_saprouter_admin_command, |
868 | 14 | { "Admin Command", "saprouter.command", FT_UINT8, BASE_DEC, VALS(saprouter_admin_command_vals), 0x0, NULL, HFILL }}, |
869 | 14 | { &hf_saprouter_admin_password, |
870 | 14 | { "Admin Command Info Password", "saprouter.password", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
871 | 14 | { &hf_saprouter_admin_client_count_short, |
872 | 14 | { "Admin Command Client Count", "saprouter.client_count", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
873 | 14 | { &hf_saprouter_admin_client_count_int, |
874 | 14 | { "Admin Command Client Count", "saprouter.client_count", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
875 | 14 | { &hf_saprouter_admin_client_ids, |
876 | 14 | { "Admin Command Client IDs", "saprouter.client_ids", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
877 | 14 | { &hf_saprouter_admin_client_id, |
878 | 14 | { "Admin Command Client ID", "saprouter.client_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}, |
879 | 14 | { &hf_saprouter_admin_address_mask, |
880 | 14 | { "Admin Command Address Mask", "saprouter.address_mask", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }}, |
881 | 14 | }; |
882 | | |
883 | | /* Setup protocol subtree array */ |
884 | 14 | static int *ett[] = { |
885 | 14 | &ett_saprouter |
886 | 14 | }; |
887 | | |
888 | | /* Register the expert info */ |
889 | 14 | static ei_register_info ei[] = { |
890 | 14 | { &ei_saprouter_route_password_found, { "saprouter.routestring.password.found", PI_SECURITY, PI_WARN, "Route password found", EXPFILL }}, |
891 | 14 | { &ei_saprouter_info_password_found, { "saprouter.password.found", PI_SECURITY, PI_WARN, "Info password found", EXPFILL }}, |
892 | 14 | { &ei_saprouter_route_invalid_length, { "saprouter.routestring.routelength.invalid", PI_MALFORMED, PI_WARN, "The route string length is invalid", EXPFILL }}, |
893 | 14 | { &ei_saprouter_invalid_client_ids, { "saprouter.client_ids.invalid", PI_MALFORMED, PI_WARN, "Client IDs list is malformed", EXPFILL }}, |
894 | 14 | }; |
895 | | |
896 | 14 | module_t *saprouter_module; |
897 | 14 | expert_module_t* saprouter_expert; |
898 | | |
899 | | /* Register the protocol */ |
900 | 14 | proto_saprouter = proto_register_protocol("SAP Router Protocol", "SAPROUTER", "saprouter"); |
901 | | |
902 | 14 | proto_register_field_array(proto_saprouter, hf, array_length(hf)); |
903 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
904 | | |
905 | 14 | saprouter_expert = expert_register_protocol(proto_saprouter); |
906 | 14 | expert_register_field_array(saprouter_expert, ei, array_length(ei)); |
907 | | |
908 | 14 | register_dissector("saprouter", dissect_saprouter, proto_saprouter); |
909 | | |
910 | | /* Register the preferences */ |
911 | 14 | saprouter_module = prefs_register_protocol(proto_saprouter, proto_reg_handoff_saprouter); |
912 | | |
913 | 14 | range_convert_str(wmem_epan_scope(), &global_saprouter_port_range, SAPROUTER_PORT_RANGE, MAX_TCP_PORT); |
914 | 14 | 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); |
915 | | |
916 | 14 | 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); |
917 | | |
918 | | /* Register the tap*/ |
919 | 14 | credentials_tap = register_tap("credentials"); |
920 | | |
921 | 14 | } |
922 | | |
923 | | |
924 | | /** |
925 | | * Helpers for dealing with the port range |
926 | | */ |
927 | | static void range_delete_callback (uint32_t port, void *ptr _U_) |
928 | 0 | { |
929 | 0 | dissector_delete_uint("sapni.port", port, saprouter_handle); |
930 | 0 | } |
931 | | |
932 | | static void range_add_callback (uint32_t port, void *ptr _U_) |
933 | 28 | { |
934 | 28 | dissector_add_uint("sapni.port", port, saprouter_handle); |
935 | 28 | } |
936 | | |
937 | | |
938 | | /** |
939 | | * Register Hand off for the SAP Router Protocol |
940 | | */ |
941 | | void |
942 | | proto_reg_handoff_saprouter(void) |
943 | 14 | { |
944 | 14 | static bool initialized = false; |
945 | 14 | static range_t *saprouter_port_range; |
946 | | |
947 | 14 | if (!initialized) { |
948 | 14 | saprouter_handle = create_dissector_handle(dissect_saprouter, proto_saprouter); |
949 | 14 | initialized = true; |
950 | 14 | } else { |
951 | 0 | range_foreach(saprouter_port_range, range_delete_callback, NULL); |
952 | 0 | wmem_free(wmem_epan_scope(), saprouter_port_range); |
953 | 0 | } |
954 | | |
955 | 14 | saprouter_port_range = range_copy(wmem_epan_scope(), global_saprouter_port_range); |
956 | 14 | range_foreach(saprouter_port_range, range_add_callback, NULL); |
957 | | |
958 | 14 | } |
959 | | |
960 | | /* |
961 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
962 | | * |
963 | | * Local variables: |
964 | | * c-basic-offset: 8 |
965 | | * tab-width: 8 |
966 | | * indent-tabs-mode: t |
967 | | * End: |
968 | | * |
969 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
970 | | * :indentSize=8:tabSize=8:noTabs=false: |
971 | | */ |