Ethereal-dev: [Ethereal-dev] [patch] network dissector for rsync
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Brad Hards <bhards@xxxxxxxxxxxxxx>
Date: Sun, 16 Feb 2003 21:40:00 +1100
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 G'day. Please find attached a basic ethereal dissector for the rsync network (client/server) protocol. I have only lightly tested it. I am not sure how much more time I can spend on this, so I am releasing it "as is". Admitedly, this dissector doesn't do a real lot, but it should provide a basis for identifying further work required, including bug fixes :) Please review and apply. Brad -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.6 (GNU/Linux) Comment: For info see http://www.gnupg.org iD8DBQE+T2qBW6pHgIdAuOMRAtsQAJ4ge4dyS+LmMC6gi4kHxlk/Vdu6uQCffnzV zSSr4peT3oR0F/PyqYNKaL8= =mRpk -----END PGP SIGNATURE-----
diff -Naur -X ethereal-dontdiff clean/ethereal-0.9.9/Makefile.am ethereal-0.9.9/Makefile.am --- clean/ethereal-0.9.9/Makefile.am 2003-01-24 10:50:12.000000000 +1100 +++ ethereal-0.9.9/Makefile.am 2003-02-15 20:42:07.000000000 +1100 @@ -317,6 +317,7 @@ packet-rpl.c \ packet-rquota.c \ packet-rsh.c \ + packet-rsync.c \ packet-rstat.c \ packet-rsvp.c \ packet-rtcp.c \ diff -Naur -X ethereal-dontdiff clean/ethereal-0.9.9/Makefile.nmake ethereal-0.9.9/Makefile.nmake --- clean/ethereal-0.9.9/Makefile.nmake 2003-01-23 13:45:42.000000000 +1100 +++ ethereal-0.9.9/Makefile.nmake 2003-02-15 20:42:26.000000000 +1100 @@ -260,6 +260,7 @@ packet-rpl.c \ packet-rquota.c \ packet-rsh.c \ + packet-rsync.c \ packet-rstat.c \ packet-rsvp.c \ packet-rtcp.c \ diff -Naur -X ethereal-dontdiff clean/ethereal-0.9.9/packet-rsync.c ethereal-0.9.9/packet-rsync.c --- clean/ethereal-0.9.9/packet-rsync.c 1970-01-01 10:00:00.000000000 +1000 +++ ethereal-0.9.9/packet-rsync.c 2003-02-16 21:34:15.000000000 +1100 @@ -0,0 +1,335 @@ +/* packet-rsync.c + * Routines for rsync dissection + * [ very rough, but mininally functional ] + * Copyright 2003, Brad Hards <bradh@xxxxxxxxxxxxx> + * + * $Id: README.developer,v 1.65 2002/11/09 08:37:00 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@xxxxxxxxxxxx> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> + +#include <string.h> +#include <time.h> +#include <glib.h> + +#include <epan/packet.h> +#include <epan/strutil.h> +#include <epan/conversation.h> + +#include "prefs.h" + + +/* what states make sense here ? */ +typedef enum _rsync_state { + RSYNC_INIT = 0, + RSYNC_SERV_INIT = 1, + RSYNC_CLIENT_QUERY = 2, + RSYNC_SERV_RESPONSE = 4, + RSYNC_COMMAND = 5, + RSYNC_SERV_MOTD = 6, + RSYNC_DATA = 7, +} rsync_state_t; + +static gboolean rsync_desegment = TRUE; + +/* this is a guide to the current conversation state */ +struct rsync_conversation_data { + rsync_state_t state; +}; + +struct rsync_frame_data { + rsync_state_t state; +}; + +static int proto_rsync = -1; + +static int hf_rsync_hdr_magic = -1; +static int hf_rsync_hdr_version = -1; +static int hf_rsync_query_string = -1; +static int hf_rsync_motd_string = -1; +static int hf_rsync_response_string = -1; +static int hf_rsync_rsyncdok_string = -1; +static int hf_rsync_command_string = -1; +static int hf_rsync_data = -1; + +static gint ett_rsync = -1; + +dissector_handle_t rsync_handle; + + +#define TCP_PORT_RSYNC 873 + +static unsigned int glb_rsync_tcp_port = TCP_PORT_RSYNC; + +/* Packet dissection routine called by tcp (& udp) when port 873 detected */ +static void +dissect_rsync_encap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + gboolean desegment) +{ + conversation_t *conversation; + struct rsync_conversation_data *conversation_data; + struct rsync_frame_data *frame_data; + proto_item *ti; + proto_tree *rsync_tree; + int offset = 0; + gchar version[5]; + gchar auth_string[10]; + guint buff_length; + gchar magic_string[14]; + + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, "RSYNC"); + + if (check_col(pinfo->cinfo, COL_INFO)) + col_clear(pinfo->cinfo, COL_INFO); + + conversation = find_conversation(&pinfo->src, &pinfo->dst, pinfo->ptype, + pinfo->srcport, pinfo->destport, 0); + if (conversation == NULL) { + conversation = conversation_new(&pinfo->src, &pinfo->dst, + pinfo->ptype, pinfo->srcport, + pinfo->destport, 0); + conversation_data = malloc(sizeof(struct rsync_conversation_data)); + conversation_data->state = RSYNC_INIT; + conversation_add_proto_data(conversation, proto_rsync, conversation_data); + } + + conversation_set_dissector(conversation, rsync_handle); + + ti = proto_tree_add_item(tree, proto_rsync, tvb, 0, -1, FALSE); + + rsync_tree = proto_item_add_subtree(ti, ett_rsync); + + conversation_data = conversation_get_proto_data(conversation, proto_rsync); + + frame_data = p_get_proto_data(pinfo->fd, proto_rsync); + if (!frame_data) { + /* then we haven't seen this frame before */ + frame_data = malloc(sizeof(struct rsync_frame_data)); + frame_data->state = conversation_data->state; + p_add_proto_data(pinfo->fd, proto_rsync, frame_data); + } + + switch (frame_data->state) { + case RSYNC_INIT: + proto_tree_add_item(rsync_tree, hf_rsync_hdr_magic, tvb, offset, 8, TRUE); + offset += 8; + proto_tree_add_item(rsync_tree, hf_rsync_hdr_version, tvb, offset, 4, TRUE); + tvb_get_nstringz0(tvb, offset, 3, version); + offset += 4; + + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, + "Client Initialisation (Version %s)", + version); + } + + conversation_data->state = RSYNC_SERV_INIT; + conversation_add_proto_data(conversation, proto_rsync, conversation_data); + + break; + case RSYNC_SERV_INIT: + proto_tree_add_item(rsync_tree, hf_rsync_hdr_magic, tvb, offset, 8, TRUE); + offset += 8; + proto_tree_add_item(rsync_tree, hf_rsync_hdr_version, tvb, offset, 4, TRUE); + tvb_get_nstringz0(tvb, offset, 3, version); + offset += 4; + + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, + "Server Initialisation (Version %s)", + version); + } + + conversation_data->state = RSYNC_CLIENT_QUERY; + conversation_add_proto_data(conversation, proto_rsync, conversation_data); + + break; + case RSYNC_CLIENT_QUERY: + proto_tree_add_item(rsync_tree, hf_rsync_query_string, tvb, offset, -1, TRUE); + + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_str(pinfo->cinfo, COL_INFO, "Client Query"); + } + + conversation_data->state = RSYNC_SERV_MOTD; + conversation_add_proto_data(conversation, proto_rsync, conversation_data); + + break; + case RSYNC_SERV_MOTD: + proto_tree_add_item(rsync_tree, hf_rsync_motd_string, tvb, offset, -1, TRUE); + + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, "Server MOTD"); + } + + conversation_data->state = RSYNC_SERV_RESPONSE; + conversation_add_proto_data(conversation, proto_rsync, conversation_data); + + break; + case RSYNC_SERV_RESPONSE: + /* there are two cases - file list, or authentication */ + tvb_get_nstringz0(tvb, offset, 8, auth_string); + if (0 == strncmp("@RSYNCD:", auth_string, 8)) { + /* matches, so we assume its an authentication message */ + /* needs to handle the AUTHREQD case, but doesn't - FIXME */ + proto_tree_add_item(rsync_tree, hf_rsync_rsyncdok_string, tvb, offset, -1, TRUE); + + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_str(pinfo->cinfo, COL_INFO, "Authenication"); + } + conversation_data->state = RSYNC_COMMAND; + + } else { /* it didn't match, so it is probably a module list */ + + proto_tree_add_item(rsync_tree, hf_rsync_response_string, tvb, offset, -1, TRUE); + + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_fstr(pinfo->cinfo, COL_INFO, "Module list"); + } + + /* we need to check the end of the buffer for magic string */ + buff_length = tvb_length_remaining(tvb, offset); + tvb_get_nstringz0(tvb, buff_length-14, 14, magic_string); + if (0 == strncmp("@RSYNCD: EXIT", magic_string, 14)) { + /* that's all, folks */ + conversation_data->state = RSYNC_COMMAND; + } else { /* there must be more data */ + conversation_data->state = RSYNC_SERV_RESPONSE; + } + } + + conversation_add_proto_data(conversation, proto_rsync, conversation_data); + + break; + + case RSYNC_COMMAND: + if (pinfo->destport == glb_rsync_tcp_port) { + /* then we are still sending commands */ + proto_tree_add_item(rsync_tree, hf_rsync_command_string, tvb, offset, -1, TRUE); + + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_str(pinfo->cinfo, COL_INFO, "Command"); + } + + conversation_data->state = RSYNC_COMMAND; + conversation_add_proto_data(conversation, proto_rsync, conversation_data); + + break; + } /* else we fall through to the data phase */ + + case RSYNC_DATA: + /* then we are still sending commands */ + proto_tree_add_item(rsync_tree, hf_rsync_data, tvb, offset, -1, TRUE); + + if (check_col(pinfo->cinfo, COL_INFO)) { + col_append_str(pinfo->cinfo, COL_INFO, "Data"); + } + + conversation_data->state = RSYNC_DATA; + conversation_add_proto_data(conversation, proto_rsync, conversation_data); + + break; + + } + +} + +/* Packet dissection routine called by tcp (& udp) when port 873 detected */ +static void +dissect_rsync(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + dissect_rsync_encap(tvb, pinfo, tree, rsync_desegment); +} + +/* Register protocol with Ethereal. */ +void +proto_register_rsync(void) +{ + static hf_register_info hf[] = { + {&hf_rsync_hdr_magic, + {"Magic Header", "rsync.hdr_magic", + FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL } + }, + {&hf_rsync_hdr_version, + {"Header Version", "rsync.hdr_version", + FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL } + }, + {&hf_rsync_query_string, + {"Client Query String", "rsync.query", + FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL } + }, + {&hf_rsync_response_string, + {"Server Response String", "rsync.response", + FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL } + }, + {&hf_rsync_motd_string, + {"Server MOTD String", "rsync.motd", + FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL } + }, + {&hf_rsync_rsyncdok_string, + {"RSYNCD Response String", "rsync.response", + FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL } + }, + {&hf_rsync_command_string, + {"Command String", "rsync.command", + FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL } + }, + {&hf_rsync_data, + {"rsync data", "rsync.data", + FT_BYTES, BASE_NONE, NULL, 0x0, "", HFILL } + }, + + }; + + static gint *ett[] = { + &ett_rsync, + }; + + module_t *rsync_module; + + proto_rsync = proto_register_protocol("RSYNC File Synchroniser", + "RSYNC", "rsync"); + proto_register_field_array(proto_rsync, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + rsync_module = prefs_register_protocol(proto_rsync, NULL); + prefs_register_uint_preference(rsync_module, "tcp.port", + "rsync TCP Port", + "Set the TCP port for RSYNC messages", + 10, + &glb_rsync_tcp_port); + prefs_register_bool_preference(rsync_module, "desegment", + "Desegment all RSYNC messages spanning multiple TCP segments", + "Whether the RSYNC dissector should desegment all messages spanning multiple TCP segments", + &rsync_desegment); +} +void +proto_reg_handoff_rsync(void) +{ + rsync_handle = create_dissector_handle(dissect_rsync, proto_rsync); + dissector_add("tcp.port", glb_rsync_tcp_port, rsync_handle); +}
- Prev by Date: Re: [Ethereal-dev] packet-giop.c enhancements: ServiceContexts, RTCORBA priorities
- Next by Date: [Ethereal-dev] Ring buffer capture causes "corrupt" captures
- Previous by thread: [Ethereal-dev] Patch: Handing of auth padding with encrypted DCE/RPC
- Next by thread: [Ethereal-dev] Ring buffer capture causes "corrupt" captures
- Index(es):