2 * Routines for MAC-Telnet dissection
3 * Copyright 2010, Haakon Nessjoen <haakon.nessjoen@gmail.com>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * Thanks to "omniflux" for dissecting the protocol by hand before me.
28 * http://www.omniflux.com/devel/mikrotik/Mikrotik_MAC_Telnet_Procotol.txt
35 #include <epan/packet.h>
36 #include <epan/prefs.h>
38 #define PROTO_TAG_MACTELNET "MAC-Telnet"
40 void proto_reg_handoff_mactelnet(void);
42 /* Initialize the protocol and registered fields */
43 static gint proto_mactelnet
= -1;
44 static gint hf_mactelnet_control_packet
= -1;
45 static gint hf_mactelnet_type
= -1;
46 static gint hf_mactelnet_protocolver
= -1;
47 static gint hf_mactelnet_source_mac
= -1;
48 static gint hf_mactelnet_destination_mac
= -1;
49 static gint hf_mactelnet_session_id
= -1;
50 static gint hf_mactelnet_client_type
= -1;
51 static gint hf_mactelnet_databytes
= -1;
52 static gint hf_mactelnet_datatype
= -1;
53 static gint hf_mactelnet_control
= -1;
54 static gint hf_mactelnet_control_length
= -1;
55 static gint hf_mactelnet_control_encryption_key
= -1;
56 static gint hf_mactelnet_control_password
= -1;
57 static gint hf_mactelnet_control_username
= -1;
58 static gint hf_mactelnet_control_terminal
= -1;
59 static gint hf_mactelnet_control_width
= -1;
60 static gint hf_mactelnet_control_height
= -1;
62 /* Global port preference */
63 static guint global_mactelnet_port
= 20561;
65 /* Control packet definition */
66 static const guint32 control_packet
= 0x563412FF;
68 /* Initialize the subtree pointers */
69 static gint ett_mactelnet
= -1;
70 static gint ett_mactelnet_control
= -1;
72 static dissector_handle_t data_handle
;
75 static const value_string packettypenames
[] = {
76 { 0, "Start session" },
79 { 4, "Ping request" },
80 { 5, "Ping response" },
81 { 255, "End session" },
85 /* Known client types */
86 static const value_string clienttypenames
[] = {
87 { 0x0015, "MAC Telnet" },
92 /* Known control-packet types */
93 static const value_string controlpackettypenames
[] = {
94 { 0, "Begin authentication" },
95 { 1, "Encryption key" },
98 { 4, "Terminal type" },
99 { 5, "Terminal width" },
100 { 6, "Terminal height" },
101 { 9, "End authentication" },
107 dissect_mactelnet(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
109 proto_item
*mactelnet_item
;
110 proto_tree
*mactelnet_tree
;
111 proto_item
*mactelnet_control_item
;
112 proto_tree
*mactelnet_control_tree
;
114 int foundclient
= -1;
115 int foundserver
= -1;
118 /* Check that there's enough data */
119 if (tvb_length(tvb
) < 18)
122 /* Get the type byte */
123 type
= tvb_get_guint8(tvb
, 1);
125 if ((type
== 4) || (type
== 5)) { /* Ping */
129 while (clienttypenames
[i
].strptr
!= NULL
) {
130 if (tvb_get_ntohs(tvb
, 14) == clienttypenames
[i
].value
) {
134 if (tvb_get_ntohs(tvb
, 16) == clienttypenames
[i
].value
) {
142 /* Not a mactelnet packet */
143 if ((foundping
< 0) && (foundclient
< 0) && (foundserver
< 0)) {
147 /* Make entries in Protocol column and Info column on summary display */
148 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, PROTO_TAG_MACTELNET
);
150 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s > %s Direction: %s Type: %s",
151 tvb_ether_to_str(tvb
, 2),
152 tvb_ether_to_str(tvb
, 8),
153 ((foundclient
>= 0) || (type
== 4) ? "Client->Server" : "Server->Client" ),
154 val_to_str(type
, packettypenames
, "Unknown Type:0x%02x")
160 /* create display subtree for the protocol */
161 mactelnet_item
= proto_tree_add_item(tree
, proto_mactelnet
, tvb
, 0, -1, ENC_NA
);
162 mactelnet_tree
= proto_item_add_subtree(mactelnet_item
, ett_mactelnet
);
165 proto_tree_add_item(mactelnet_tree
, hf_mactelnet_protocolver
, tvb
, offset
, 1, ENC_NA
);
169 proto_tree_add_item(mactelnet_tree
, hf_mactelnet_type
, tvb
, offset
, 1, ENC_NA
);
173 proto_tree_add_item(mactelnet_tree
, hf_mactelnet_source_mac
, tvb
, offset
, 6, ENC_NA
);
177 proto_tree_add_item(mactelnet_tree
, hf_mactelnet_destination_mac
, tvb
, offset
, 6, ENC_NA
);
180 if (foundserver
>= 0) {
181 /* Server to client */
184 proto_tree_add_item(mactelnet_tree
, hf_mactelnet_session_id
, tvb
, offset
+2, 2, ENC_BIG_ENDIAN
);
188 proto_tree_add_item(mactelnet_tree
, hf_mactelnet_client_type
, tvb
, offset
-2, 2, ENC_BIG_ENDIAN
);
190 } else if (foundclient
>= 0) {
191 /* Client to server */
194 proto_tree_add_item(mactelnet_tree
, hf_mactelnet_session_id
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
198 proto_tree_add_item(mactelnet_tree
, hf_mactelnet_client_type
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
200 } else if (foundping
>= 0) {
201 /* Skip empty data */
207 proto_tree_add_item(mactelnet_tree
, hf_mactelnet_databytes
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
211 /* Data packets only */
213 while(tvb_reported_length_remaining(tvb
, offset
) > 0) {
214 if ((tvb_reported_length_remaining(tvb
, offset
) > 4) && (tvb_get_ntohl(tvb
, offset
) == control_packet
)) {
218 /* Add subtree for control packet */
219 mactelnet_control_item
= proto_tree_add_item(mactelnet_tree
, hf_mactelnet_control
, tvb
, offset
, -1, ENC_NA
);
220 mactelnet_control_tree
= proto_item_add_subtree(mactelnet_control_item
, ett_mactelnet
);
221 /* Control packet magic number (4) */
222 proto_tree_add_item(mactelnet_control_tree
, hf_mactelnet_control_packet
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
225 /* Control packet type (1) */
226 datatype
= tvb_get_guint8(tvb
, offset
);
227 proto_tree_add_item(mactelnet_control_tree
, hf_mactelnet_datatype
, tvb
, offset
, 1, ENC_NA
);
230 /* Control packet length (4) */
231 datalength
= tvb_get_ntohl(tvb
, offset
);
232 proto_tree_add_item(mactelnet_control_tree
, hf_mactelnet_control_length
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
236 case 1: /* Encryption Key */
237 proto_tree_add_item(mactelnet_control_tree
, hf_mactelnet_control_encryption_key
, tvb
, offset
, datalength
, ENC_NA
);
240 case 2: /* Password */
241 proto_tree_add_item(mactelnet_control_tree
, hf_mactelnet_control_password
, tvb
, offset
, datalength
, ENC_NA
);
244 case 3: /* Username */
245 proto_tree_add_item(mactelnet_control_tree
, hf_mactelnet_control_username
, tvb
, offset
, datalength
, ENC_ASCII
|ENC_NA
);
248 case 4: /* Terminal type */
249 proto_tree_add_item(mactelnet_control_tree
, hf_mactelnet_control_terminal
, tvb
, offset
, datalength
, ENC_ASCII
|ENC_NA
);
252 case 5: /* Terminal width */
253 proto_tree_add_item(mactelnet_control_tree
, hf_mactelnet_control_width
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
256 case 6: /* Terminal height */
257 proto_tree_add_item(mactelnet_control_tree
, hf_mactelnet_control_height
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
260 case 9: /* End authentication (no data) */
263 proto_item_set_len (mactelnet_control_item
, datalength
+ 9);
264 offset
+= datalength
;
266 /* Data packet, let wireshark handle it */
267 tvbuff_t
*next_client
= tvb_new_subset_remaining(tvb
, offset
);
268 return call_dissector(data_handle
, next_client
, pinfo
, mactelnet_tree
);
271 } else if ((type
== 4) || (type
== 5)) {
272 /* Data packet, let wireshark handle it */
273 tvbuff_t
*next_client
= tvb_new_subset_remaining(tvb
, offset
);
274 return call_dissector(data_handle
, next_client
, pinfo
, mactelnet_tree
);
279 return tvb_reported_length(tvb
);
284 proto_register_mactelnet(void)
286 static hf_register_info hf
[] = {
287 { &hf_mactelnet_control_packet
,
288 { "Control Packet Magic Number", "mactelnet.control_packet",
289 FT_UINT32
, BASE_HEX
, NULL
, 0x0,
292 { &hf_mactelnet_type
,
293 { "Type", "mactelnet.type",
294 FT_UINT8
, BASE_DEC
, VALS(packettypenames
), 0x0,
295 "Packet Type", HFILL
}
297 { &hf_mactelnet_protocolver
,
298 { "Protocol Version", "mactelnet.protocol_version",
299 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
302 { &hf_mactelnet_source_mac
,
303 { "Source MAC", "mactelnet.source_mac",
304 FT_ETHER
, BASE_NONE
, NULL
, 0x0,
307 { &hf_mactelnet_destination_mac
,
308 { "Destination MAC", "mactelnet.destination_mac",
309 FT_ETHER
, BASE_NONE
, NULL
, 0x0,
312 { &hf_mactelnet_session_id
,
313 { "Session ID", "mactelnet.session_id",
314 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
315 "Session ID for this connection", HFILL
}
317 { &hf_mactelnet_client_type
,
318 { "Client Type", "mactelnet.client_type",
319 FT_UINT16
, BASE_HEX
, VALS(clienttypenames
) , 0x0,
322 { &hf_mactelnet_databytes
,
323 { "Session Data Bytes", "mactelnet.session_bytes",
324 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
325 "Session data bytes received", HFILL
}
327 { &hf_mactelnet_datatype
,
328 { "Data Packet Type", "mactelnet.data_type",
329 FT_UINT8
, BASE_HEX
, VALS(controlpackettypenames
) , 0x0,
332 { &hf_mactelnet_control
,
333 { "Control Packet", "mactelnet.control",
334 FT_NONE
, BASE_NONE
, NULL
, 0x0,
337 { &hf_mactelnet_control_length
,
338 { "Control Data Length", "mactelnet.control_length",
339 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
340 "Control packet length", HFILL
}
342 { &hf_mactelnet_control_encryption_key
,
343 { "Encryption Key", "mactelnet.control_encryptionkey",
344 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
345 "Login encryption key", HFILL
}
347 { &hf_mactelnet_control_password
,
348 { "Password MD5", "mactelnet.control_password",
349 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
350 "Null padded MD5 password", HFILL
}
352 { &hf_mactelnet_control_username
,
353 { "Username", "mactelnet.control_username",
354 FT_STRING
, BASE_NONE
, NULL
, 0x0,
357 { &hf_mactelnet_control_terminal
,
358 { "Terminal Type", "mactelnet.control_terminaltype",
359 FT_STRING
, BASE_NONE
, NULL
, 0x0,
362 { &hf_mactelnet_control_width
,
363 { "Terminal Width", "mactelnet.control_width",
364 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
367 { &hf_mactelnet_control_height
,
368 { "Terminal Height", "mactelnet.control_height",
369 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
374 /* Setup protocol subtree array */
375 static gint
*ett
[] = {
377 &ett_mactelnet_control
,
380 module_t
*mactelnet_module
;
382 /* Register the protocol name and description */
383 proto_mactelnet
= proto_register_protocol ("MikroTik MAC-Telnet Protocol", PROTO_TAG_MACTELNET
, "mactelnet");
385 /* Required function calls to register the header fields and subtrees used */
386 proto_register_field_array (proto_mactelnet
, hf
, array_length (hf
));
387 proto_register_subtree_array (ett
, array_length (ett
));
389 mactelnet_module
= prefs_register_protocol(proto_mactelnet
, proto_reg_handoff_mactelnet
);
391 prefs_register_uint_preference(mactelnet_module
, "port", "UDP Port",
392 "MAC-Telnet UDP port if other than the default",
393 10, &global_mactelnet_port
);
397 proto_reg_handoff_mactelnet(void)
399 static gboolean initialized
= FALSE
;
400 static guint current_port
;
401 static dissector_handle_t mactelnet_handle
;
404 mactelnet_handle
= new_create_dissector_handle(dissect_mactelnet
, proto_mactelnet
);
405 data_handle
= find_dissector("data");
408 dissector_delete_uint("udp.port", current_port
, mactelnet_handle
);
411 current_port
= global_mactelnet_port
;
412 dissector_add_uint("udp.port", current_port
, mactelnet_handle
);