MSWSP: add two more Property Sets
[wireshark-wip.git] / epan / dissectors / packet-rsync.c
blobbf57b937f64c6c29c25e7213ee3a136e616c1280
1 /* packet-rsync.c
2 * Routines for rsync dissection
3 * [ very rough, but mininally functional ]
4 * Copyright 2003, Brad Hards <bradh@frogmouth.net>
6 * $Id$
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
29 #include "config.h"
31 #include <string.h>
33 #include <glib.h>
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 {
55 RSYNC_INIT = 0,
56 RSYNC_SERV_INIT = 1,
57 RSYNC_CLIENT_QUERY = 2,
58 RSYNC_MODULE_LIST = 4,
59 RSYNC_COMMAND = 5,
60 RSYNC_SERV_MOTD = 6,
61 RSYNC_DATA = 7
62 } rsync_state_t;
64 enum rsync_who {
65 CLIENT,
66 SERVER
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 {
78 rsync_state_t state;
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;
126 static void
127 dissect_rsync_version_header(tvbuff_t *tvb, packet_info *pinfo, proto_tree *rsync_tree, enum rsync_who me)
129 int offset = 0;
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 */
141 static int
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;
148 proto_item *ti;
149 proto_tree *rsync_tree;
150 enum rsync_who me;
151 int offset = 0;
152 guint buff_length;
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);
185 if (me == SERVER) {
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;
192 break;
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;
201 break;
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;
229 break;
231 case RSYNC_DATA:
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;
238 break;
240 default:
241 /* Unknown state */
242 break;
244 } else { /* me == CLIENT */
245 switch (rsync_frame_data_p->state) {
246 case RSYNC_INIT:
247 dissect_rsync_version_header(tvb, pinfo, rsync_tree, me);
249 conversation_data->client_state = RSYNC_CLIENT_QUERY;
251 break;
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;
263 } else {
264 conversation_data->server_state = RSYNC_DATA;
267 break;
269 case RSYNC_COMMAND:
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;
277 break;
279 case RSYNC_DATA:
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;
287 break;
289 default:
290 /* Unknown state */
291 break;
294 return tvb_length(tvb);
297 /* Packet dissection routine called by tcp (& udp) when port 873 detected */
298 static int
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);
308 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,
320 &hfi_rsync_data,
322 #endif
324 static gint *ett[] = {
325 &ett_rsync,
328 module_t *rsync_module;
330 int proto_rsync;
332 proto_rsync = proto_register_protocol("RSYNC File Synchroniser",
333 "RSYNC", "rsync");
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",
341 "rsync 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.",
349 &rsync_desegment);
351 rsync_handle = new_create_dissector_handle(dissect_rsync, proto_rsync);
353 void
354 proto_reg_handoff_rsync(void)
356 static gboolean initialized = FALSE;
357 static guint saved_rsync_tcp_port;
359 if (!initialized) {
360 initialized = TRUE;
361 } else {
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
372 * Local variables:
373 * c-basic-offset: 4
374 * tab-width: 8
375 * indent-tabs-mode: nil
376 * End:
378 * vi: set shiftwidth=4 tabstop=8 expandtab:
379 * :indentSize=4:tabSize=8:noTabs=true: