2 * Routines for rsync dissection
3 * [ very rough, but mininally functional ]
4 * Copyright 2003, Brad Hards <bradh@frogmouth.net>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #define NEW_PROTO_TREE_API
35 #include <epan/packet.h>
36 #include <epan/strutil.h>
37 #include <epan/conversation.h>
38 #include <epan/wmem/wmem.h>
39 #include <epan/prefs.h>
41 #define RSYNCD_MAGIC_HEADER "@RSYNCD:"
42 #define RSYNCD_MAGIC_HEADER_LEN 8
44 #define RSYNCD_AUTHREQD "@RSYNCD: AUTHREQD "
45 #define RSYNCD_AUTHREQD_LEN 18
47 #define RSYNCD_EXIT "@RSYNCD: EXIT"
48 #define RSYNCD_EXIT_LEN 13
50 #define RSYNC_MODULE_LIST_QUERY "\n"
51 #define RSYNC_MODULE_LIST_QUERY_LEN 1
53 /* what states make sense here ? */
54 typedef enum _rsync_state
{
57 RSYNC_CLIENT_QUERY
= 2,
58 RSYNC_MODULE_LIST
= 4,
69 static gboolean rsync_desegment
= TRUE
;
71 /* this is a guide to the current conversation state */
72 struct rsync_conversation_data
{
73 rsync_state_t client_state
;
74 rsync_state_t server_state
;
77 struct rsync_frame_data
{
81 static header_field_info
*hfi_rsync
= NULL
;
83 #define RSYNC_HF_INIT HFI_INIT(proto_rsync)
85 static header_field_info hfi_rsync_hdr_magic RSYNC_HF_INIT
=
86 {"Magic Header", "rsync.hdr_magic",
87 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
};
89 static header_field_info hfi_rsync_hdr_version RSYNC_HF_INIT
=
90 {"Header Version", "rsync.hdr_version",
91 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
};
93 static header_field_info hfi_rsync_query_string RSYNC_HF_INIT
=
94 {"Client Query String", "rsync.query",
95 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
};
97 static header_field_info hfi_rsync_motd_string RSYNC_HF_INIT
=
98 {"Server MOTD String", "rsync.motd",
99 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
};
101 static header_field_info hfi_rsync_module_list_string RSYNC_HF_INIT
=
102 {"Server Module List", "rsync.module_list",
103 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
};
105 static header_field_info hfi_rsync_rsyncdok_string RSYNC_HF_INIT
=
106 {"RSYNCD Response String", "rsync.response",
107 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
};
109 static header_field_info hfi_rsync_command_string RSYNC_HF_INIT
=
110 {"Client Command String", "rsync.command",
111 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
};
113 static header_field_info hfi_rsync_data RSYNC_HF_INIT
=
114 {"rsync data", "rsync.data",
115 FT_BYTES
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
};
117 static gint ett_rsync
= -1;
119 static dissector_handle_t rsync_handle
;
122 #define TCP_PORT_RSYNC 873
124 static guint glb_rsync_tcp_port
= TCP_PORT_RSYNC
;
127 dissect_rsync_version_header(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*rsync_tree
, enum rsync_who me
)
130 gchar version
[5]; /* 2 digits for main version; '.'; 1 digit for sub version; NULL */
131 proto_tree_add_item(rsync_tree
, &hfi_rsync_hdr_magic
, tvb
, offset
, RSYNCD_MAGIC_HEADER_LEN
, ENC_ASCII
|ENC_NA
);
132 offset
+= RSYNCD_MAGIC_HEADER_LEN
;
133 offset
++; /* skip the space */
134 proto_tree_add_item(rsync_tree
, &hfi_rsync_hdr_version
, tvb
, offset
, sizeof(version
)-1, ENC_ASCII
|ENC_NA
);
135 tvb_get_nstringz0(tvb
, offset
, sizeof(version
), version
);
137 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%s Initialisation (Version %s)", (me
== SERVER
? "Server" : "Client"), version
);
140 /* Packet dissection routine called by tcp (& udp) when port 873 detected */
142 dissect_rsync_encap(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
143 gboolean desegment _U_
)
145 conversation_t
*conversation
;
146 struct rsync_conversation_data
*conversation_data
;
147 struct rsync_frame_data
*rsync_frame_data_p
;
149 proto_tree
*rsync_tree
;
154 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "RSYNC");
156 col_clear(pinfo
->cinfo
, COL_INFO
);
158 me
= pinfo
->srcport
== glb_rsync_tcp_port
? SERVER
: CLIENT
;
160 conversation
= find_or_create_conversation(pinfo
);
162 conversation_data
= (struct rsync_conversation_data
*)conversation_get_proto_data(conversation
, hfi_rsync
->id
);
164 if (conversation_data
== NULL
) { /* new conversation */
165 conversation_data
= wmem_new(wmem_file_scope(), struct rsync_conversation_data
);
166 conversation_data
->client_state
= RSYNC_INIT
;
167 conversation_data
->server_state
= RSYNC_SERV_INIT
;
168 conversation_add_proto_data(conversation
, hfi_rsync
->id
, conversation_data
);
171 conversation_set_dissector(conversation
, rsync_handle
);
173 ti
= proto_tree_add_item(tree
, hfi_rsync
, tvb
, 0, -1, ENC_NA
);
175 rsync_tree
= proto_item_add_subtree(ti
, ett_rsync
);
177 rsync_frame_data_p
= (struct rsync_frame_data
*)p_get_proto_data(pinfo
->fd
, hfi_rsync
->id
, 0);
178 if (!rsync_frame_data_p
) {
179 /* then we haven't seen this frame before */
180 rsync_frame_data_p
= wmem_new(wmem_file_scope(), struct rsync_frame_data
);
181 rsync_frame_data_p
->state
= (me
== SERVER
) ? conversation_data
->server_state
: conversation_data
->client_state
;
182 p_add_proto_data(pinfo
->fd
, hfi_rsync
->id
, 0, rsync_frame_data_p
);
186 switch (rsync_frame_data_p
->state
) {
187 case RSYNC_SERV_INIT
:
188 dissect_rsync_version_header(tvb
, pinfo
, rsync_tree
, me
);
190 conversation_data
->server_state
= RSYNC_SERV_MOTD
;
194 case RSYNC_SERV_MOTD
:
195 proto_tree_add_item(rsync_tree
, &hfi_rsync_motd_string
, tvb
, offset
, -1, ENC_ASCII
|ENC_NA
);
197 col_set_str(pinfo
->cinfo
, COL_INFO
, "Server MOTD");
199 conversation_data
->server_state
= RSYNC_SERV_MOTD
;
203 case RSYNC_MODULE_LIST
:
204 /* there are two cases - file list, or authentication */
205 if (0 == tvb_strneql(tvb
, offset
, RSYNCD_AUTHREQD
, RSYNCD_AUTHREQD_LEN
)) {
206 /* matches, so we assume its an authentication message */
207 proto_tree_add_item(rsync_tree
, &hfi_rsync_rsyncdok_string
, tvb
, offset
, -1, ENC_ASCII
|ENC_NA
);
209 col_set_str(pinfo
->cinfo
, COL_INFO
, "Authentication");
210 conversation_data
->server_state
= RSYNC_DATA
;
212 } else { /* it didn't match, so it is probably a module list */
214 proto_tree_add_item(rsync_tree
, &hfi_rsync_module_list_string
, tvb
, offset
, -1, ENC_ASCII
|ENC_NA
);
216 /* we need to check the end of the buffer for magic string */
217 buff_length
= tvb_length_remaining(tvb
, offset
);
218 if (buff_length
> RSYNCD_EXIT_LEN
&&
219 0 == tvb_strneql(tvb
, buff_length
-RSYNCD_EXIT_LEN
-1, RSYNCD_EXIT
, RSYNCD_EXIT_LEN
)) {
220 /* that's all, folks */
221 col_set_str(pinfo
->cinfo
, COL_INFO
, "Final module list");
222 conversation_data
->server_state
= RSYNC_DATA
;
223 } else { /* there must be more data */
224 col_set_str(pinfo
->cinfo
, COL_INFO
, "Module list");
225 conversation_data
->server_state
= RSYNC_MODULE_LIST
;
232 proto_tree_add_item(rsync_tree
, &hfi_rsync_data
, tvb
, offset
, -1, ENC_NA
);
234 col_set_str(pinfo
->cinfo
, COL_INFO
, "Data");
236 conversation_data
->server_state
= RSYNC_DATA
;
244 } else { /* me == CLIENT */
245 switch (rsync_frame_data_p
->state
) {
247 dissect_rsync_version_header(tvb
, pinfo
, rsync_tree
, me
);
249 conversation_data
->client_state
= RSYNC_CLIENT_QUERY
;
253 case RSYNC_CLIENT_QUERY
:
254 proto_tree_add_item(rsync_tree
, &hfi_rsync_query_string
, tvb
, offset
, -1, ENC_ASCII
|ENC_NA
);
256 col_set_str(pinfo
->cinfo
, COL_INFO
, "Client Query");
258 conversation_data
->client_state
= RSYNC_COMMAND
;
260 if (tvb_length(tvb
) == RSYNC_MODULE_LIST_QUERY_LEN
&&
261 0 == tvb_strneql(tvb
, offset
, RSYNC_MODULE_LIST_QUERY
, RSYNC_MODULE_LIST_QUERY_LEN
)) {
262 conversation_data
->server_state
= RSYNC_MODULE_LIST
;
264 conversation_data
->server_state
= RSYNC_DATA
;
270 /* then we are still sending commands */
271 proto_tree_add_item(rsync_tree
, &hfi_rsync_command_string
, tvb
, offset
, -1, ENC_ASCII
|ENC_NA
);
273 col_set_str(pinfo
->cinfo
, COL_INFO
, "Client Command");
275 conversation_data
->client_state
= RSYNC_COMMAND
;
280 /* then we are still sending commands */
281 proto_tree_add_item(rsync_tree
, &hfi_rsync_data
, tvb
, offset
, -1, ENC_NA
);
283 col_set_str(pinfo
->cinfo
, COL_INFO
, "Data");
285 conversation_data
->client_state
= RSYNC_DATA
;
294 return tvb_length(tvb
);
297 /* Packet dissection routine called by tcp (& udp) when port 873 detected */
299 dissect_rsync(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
301 return dissect_rsync_encap(tvb
, pinfo
, tree
, rsync_desegment
);
304 /* Register protocol with Wireshark. */
306 void proto_reg_handoff_rsync(void);
309 proto_register_rsync(void)
311 #ifndef HAVE_HFI_SECTION_INIT
312 static header_field_info
*hfi
[] = {
313 &hfi_rsync_hdr_magic
,
314 &hfi_rsync_hdr_version
,
315 &hfi_rsync_query_string
,
316 &hfi_rsync_module_list_string
,
317 &hfi_rsync_motd_string
,
318 &hfi_rsync_rsyncdok_string
,
319 &hfi_rsync_command_string
,
324 static gint
*ett
[] = {
328 module_t
*rsync_module
;
332 proto_rsync
= proto_register_protocol("RSYNC File Synchroniser",
334 hfi_rsync
= proto_registrar_get_nth(proto_rsync
);
336 proto_register_fields(proto_rsync
, hfi
, array_length(hfi
));
337 proto_register_subtree_array(ett
, array_length(ett
));
339 rsync_module
= prefs_register_protocol(proto_rsync
, proto_reg_handoff_rsync
);
340 prefs_register_uint_preference(rsync_module
, "tcp_port",
342 "Set the TCP port for RSYNC messages",
344 &glb_rsync_tcp_port
);
345 prefs_register_bool_preference(rsync_module
, "desegment",
346 "Reassemble RSYNC messages spanning multiple TCP segments",
347 "Whether the RSYNC dissector should reassemble messages spanning multiple TCP segments."
348 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
351 rsync_handle
= new_create_dissector_handle(dissect_rsync
, proto_rsync
);
354 proto_reg_handoff_rsync(void)
356 static gboolean initialized
= FALSE
;
357 static guint saved_rsync_tcp_port
;
362 dissector_delete_uint("tcp.port", saved_rsync_tcp_port
, rsync_handle
);
365 dissector_add_uint("tcp.port", glb_rsync_tcp_port
, rsync_handle
);
366 saved_rsync_tcp_port
= glb_rsync_tcp_port
;
370 * Editor modelines - http://www.wireshark.org/tools/modelines.html
375 * indent-tabs-mode: nil
378 * vi: set shiftwidth=4 tabstop=8 expandtab:
379 * :indentSize=4:tabSize=8:noTabs=true: