From 6785ffd7965535af8f69ad2b1eea985186190795 Mon Sep 17 00:00:00 2001 From: Stephen Fisher Date: Tue, 6 Nov 2007 05:30:04 +0000 Subject: Wake on LAN (WOL): New dissector from Chris Maynard via -dev list and enhancement bug #1968 Me: Added entries in epan/etypes.h and epan/dissectors/packet-ethertype.c for WOL. svn path=/trunk/; revision=23371 --- epan/dissectors/Makefile.common | 1 + epan/dissectors/packet-ethertype.c | 1 + epan/dissectors/packet-wol.c | 366 +++++++++++++++++++++++++++++++++++++ epan/etypes.h | 4 + 4 files changed, 372 insertions(+) create mode 100644 epan/dissectors/packet-wol.c (limited to 'epan') diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common index 6898594057..6b4ce2ec42 100644 --- a/epan/dissectors/Makefile.common +++ b/epan/dissectors/Makefile.common @@ -745,6 +745,7 @@ CLEAN_DISSECTOR_SRC = \ packet-winsrepl.c \ packet-wlancap.c \ packet-wlccp.c \ + packet-wol.c \ packet-wsp.c \ packet-wtls.c \ packet-wtp.c \ diff --git a/epan/dissectors/packet-ethertype.c b/epan/dissectors/packet-ethertype.c index 34f6e862e2..ce362ab4fa 100644 --- a/epan/dissectors/packet-ethertype.c +++ b/epan/dissectors/packet-ethertype.c @@ -53,6 +53,7 @@ const value_string etype_vals[] = { {ETHERTYPE_XNS_IDP, "XNS Internet Datagram Protocol" }, {ETHERTYPE_X25L3, "X.25 Layer 3" }, {ETHERTYPE_ARP, "ARP" }, + {ETHERTYPE_WOL, "Wake on LAN" }, {ETHERTYPE_WMX_M2M, "WiMax Mac-to-Mac" }, {ETHERTYPE_EPL_V1, "EPL_V1" }, {ETHERTYPE_REVARP, "RARP" }, diff --git a/epan/dissectors/packet-wol.c b/epan/dissectors/packet-wol.c new file mode 100644 index 0000000000..5e42e999ac --- /dev/null +++ b/epan/dissectors/packet-wol.c @@ -0,0 +1,366 @@ +/* packet-wol.c + * Routines for WOL dissection + * Copyright 2007, Christopher Maynard + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This dissector for "Wake On LAN" was not copied from any other existing + * dissector. It uses the template from SVN23520 docs/README.devloper, which + * was the latest one available at the time of this writing. This dissector is + * a heuristic one though, so appropriate changes have made to the template + * as needed. + * + * The "Wake On LAN" dissector was written based primarily on the AMD white + * paper, available from: http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/20213.pdf. + * + * In addition, testing of the dissector was conducted using 2 utilities + * downloaded from http://www.moldaner.de/wakeonlan/wakeonlan.html and + * http://www.depicus.com/wake-on-lan/, as well as with the ether-wake utility + * on a Linux Fedora Core 4 system. + * + * From what I can tell from the tools available, even though the white paper + * indicates that the so-called, "MagicPacket" can be located anywhere within + * the Ethernet frame, in practice, there seem to be only 2 variations of the + * implementation of the MagicPacket. Ether-wake implements it as an Ethernet + * frame with ether type 0x0842 (ETHERTYPE_WOL), and the other tools all seem + * to implement it as a UDP packet, both with the payload as nothing but the + * MagicPacket. + * + * To keep things simple, this dissector will only indicate a frame as + * Wake-On-Lan if the MagicPacket is found for a frame marked as etherytpe + * 0x0842 or if it's a UDP packet. To fully support Wake-On-Lan dissection + * though, we would need a way to have this dissector called only if the frame + * hasn't already been classified as some other type of dissector ... but I + * don't know how to do that? The only alternative I am aware of would be to + * register as a heuristic dissector for pretty much every possible protocol + * there is, which seems unreasonable to do to me. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include + +#include +#include +#include +#include + +/* IF PROTO exposes code to other dissectors, then it must be exported + in a header file. If not, a header file is not needed at all. */ +/* #include "packet-wol.h" */ + +/* Forward declaration we need below */ +void proto_reg_handoff_wol(void); + +/* Initialize the protocol and registered fields */ +static int proto_wol = -1; +static int hf_wol_sync = -1; +static int hf_wol_mac = -1; +static int hf_wol_passwd = -1; + +/* Global sample preference ("controls" display of numbers) */ +/* static gboolean gPREF_HEX = FALSE; */ + +/* Initialize the subtree pointers */ +static gint ett_wol = -1; +static gint ett_wol_macblock = -1; + +/* Code to actually dissect the packets */ +static int +dissect_wol(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + guint len; + gint offset; + guint8 sync[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + guint8 *mac; + guint8 *passwd; + +/* Set up structures needed to add the protocol subtree and manage it */ + proto_item *ti; + proto_item *mti; + proto_tree *wol_tree; + proto_tree *mac_tree; + +/* First, if at all possible, do some heuristics to check if the packet cannot + * possibly belong to your protocol. This is especially important for + * protocols directly on top of TCP or UDP where port collisions are + * common place (e.g., even though your protocol uses a well known port, + * someone else may set up, for example, a web server on that port which, + * if someone analyzed that web server's traffic in Wireshark, would result + * in Wireshark handing an HTTP packet to your dissector). For example: + */ + /* Check that there's enough data */ + len = tvb_length(tvb); + if ( len < 102 ) /* wol's smallest packet size is 102 */ + return (0); + + /* Get some values from the packet header, probably using tvb_get_*() */ + + /* Regardless of what the AMD white paper states, don't search the entire + * tvb for the synchronization stream. My feeling is that this could be + * quite expensive and seriously hinder Wireshark performance. For now, + * unless we need to change it later, just compare the 1st 6 bytes. */ + if ( tvb_memeql(tvb, 0, sync, 6) != 0 ) + return (0); + + /* So far so good. Now get the next 6 bytes, which we'll assume is the + * target's MAC address, and do 15 memory chunk comparisons, since if this + * is a real MagicPacket, the target's MAC will be duplicated 16 times. */ + mac = ep_tvb_memdup(tvb, 6, 6); + for ( offset = 12; offset < 102; offset += 6 ) + if ( tvb_memeql(tvb, offset, mac, 6) != 0 ) + return (0); + + /* OK, we're going to assume it's a MagicPacket. If there's a password, + * grab it now, and in case there's any extra bytes after the only 3 valid + * and expected lengths, truncate the length so the extra byte(s) aren't + * included as being part of the WOL payload. */ + if ( len >= 106 && len < 108 ) + { + len = 106; + passwd = ip_to_str(ep_tvb_memdup(tvb, 102, 4)); + } + else if ( len >= 108 ) + { + len = 108; + passwd = ether_to_str(ep_tvb_memdup(tvb, 102, 6)); + } + else + { + len = 102; + passwd = NULL; + } + +/* Make entries in Protocol column and Info column on summary display */ + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, "WOL"); + +/* This field shows up as the "Info" column in the display; you should use + it, if possible, to summarize what's in the packet, so that a user looking + at the list of packets can tell what type of packet it is. See section 1.5 + for more information. + + Before changing the contents of a column you should make sure the column is + active by calling "check_col(pinfo->cinfo, COL_*)". If it is not active + don't bother setting it. + + If you are setting the column to a constant string, use "col_set_str()", + as it's more efficient than the other "col_set_XXX()" calls. + + If you're setting it to a string you've constructed, or will be + appending to the column later, use "col_add_str()". + + "col_add_fstr()" can be used instead of "col_add_str()"; it takes + "printf()"-like arguments. Don't use "col_add_fstr()" with a format + string of "%s" - just use "col_add_str()" or "col_set_str()", as it's + more efficient than "col_add_fstr()". + + If you will be fetching any data from the packet before filling in + the Info column, clear that column first, in case the calls to fetch + data from the packet throw an exception because they're fetching data + past the end of the packet, so that the Info column doesn't have data + left over from the previous dissector; do + + if (check_col(pinfo->cinfo, COL_INFO)) + col_clear(pinfo->cinfo, COL_INFO); + + */ + + if ( check_col(pinfo->cinfo, COL_INFO) ) + { + col_clear(pinfo->cinfo, COL_INFO); + col_add_fstr(pinfo->cinfo, COL_INFO, "MagicPacket for %s (%s)", + get_ether_name(mac), ether_to_str(mac)); + + /* NOTE: ether-wake uses a dotted-decimal format for specifying a + * 4-byte password or an Ethernet mac address format for specifying + * a 6-byte password, so display them in that format, even if the + * password isn't really an IP or MAC address. */ + if ( passwd ) + col_append_fstr(pinfo->cinfo, COL_INFO, ", password %s", passwd); + } + +/* A protocol dissector can be called in 2 different ways: + + (a) Operational dissection + + In this mode, Wireshark is only interested in the way protocols + interact, protocol conversations are created, packets are + reassembled and handed over to higher-level protocol dissectors. + In this mode Wireshark does not build a so-called "protocol + tree". + + (b) Detailed dissection + + In this mode, Wireshark is also interested in all details of + a given protocol, so a "protocol tree" is created. + + Wireshark distinguishes between the 2 modes with the proto_tree pointer: + (a) <=> tree == NULL + (b) <=> tree != NULL + + In the interest of speed, if "tree" is NULL, avoid building a + protocol tree and adding stuff to it, or even looking at any packet + data needed only if you're building the protocol tree, if possible. + + Note, however, that you must fill in column information, create + conversations, reassemble packets, build any other persistent state + needed for dissection, and call subdissectors regardless of whether + "tree" is NULL or not. This might be inconvenient to do without + doing most of the dissection work; the routines for adding items to + the protocol tree can be passed a null protocol tree pointer, in + which case they'll return a null item pointer, and + "proto_item_add_subtree()" returns a null tree pointer if passed a + null item pointer, so, if you're careful not to dereference any null + tree or item pointers, you can accomplish this by doing all the + dissection work. This might not be as efficient as skipping that + work if you're not building a protocol tree, but if the code would + have a lot of tests whether "tree" is null if you skipped that work, + you might still be better off just doing all that work regardless of + whether "tree" is null or not. */ + if (tree) { + +/* NOTE: The offset and length values in the call to + "proto_tree_add_item()" define what data bytes to highlight in the hex + display window when the line in the protocol tree display + corresponding to that item is selected. + + Supplying a length of -1 is the way to highlight all data from the + offset to the end of the packet. */ + +/* create display subtree for the protocol */ + ti = proto_tree_add_item(tree, proto_wol, tvb, 0, len, FALSE); + proto_item_append_text(ti, ", MAC: %s (%s)", get_ether_name(mac), + ether_to_str(mac)); + if ( passwd ) + proto_item_append_text(ti, ", password: %s", passwd); + wol_tree = proto_item_add_subtree(ti, ett_wol); + +/* add an item to the subtree, see section 1.6 for more information */ + proto_tree_add_item(wol_tree, hf_wol_sync, tvb, 0, 6, FALSE); + +/* Continue adding tree items to process the packet here */ + mti = proto_tree_add_text(wol_tree, tvb, 6, 96, "MAC: %s (%s)", + get_ether_name(mac), ether_to_str(mac)); + mac_tree = proto_item_add_subtree(mti, ett_wol_macblock); + for ( offset = 6; offset < 102; offset += 6 ) + proto_tree_add_ether(mac_tree, hf_wol_mac, tvb, offset, 6, mac); + + if ( len == 106 ) + proto_tree_add_bytes_format(wol_tree, hf_wol_passwd, tvb, offset, + 4, passwd, "Password: %s", passwd); + else if ( len == 108 ) + proto_tree_add_bytes_format(wol_tree, hf_wol_passwd, tvb, offset, + 6, passwd, "Password: %s", passwd); + } + +/* If this protocol has a sub-dissector call it here, see section 1.8 */ + +/* Return the amount of data this dissector was able to dissect */ + if ( pinfo->ethertype == ETHERTYPE_WOL ) + return (len); + + /* Heuristic dissectors return TRUE/FALSE. */ + return (TRUE); +} + + +/* Register the protocol with Wireshark */ + +/* this format is require because a script is used to build the C function + that calls all the protocol registration. +*/ + +void +proto_register_wol(void) +{ +/* Setup list of header fields See Section 1.6.1 for details*/ + static hf_register_info hf[] = { + { &hf_wol_sync, + { "Sync stream", "wol.sync", + FT_BYTES, BASE_HEX, NULL, 0, "", HFILL }}, + { &hf_wol_mac, + { "MAC", "wol.mac", + FT_ETHER, BASE_HEX, NULL, 0, "", HFILL }}, + { &hf_wol_passwd, + { "Password", "wol.passwd", + FT_BYTES, BASE_HEX, NULL, 0, "", HFILL }} + }; + +/* Setup protocol subtree array */ + static gint *ett[] = { + &ett_wol, + &ett_wol_macblock + }; + +/* Register the protocol name and description */ + proto_wol = proto_register_protocol("Wake On LAN", "WOL", "wol"); + +/* Required function calls to register the header fields and subtrees used */ + proto_register_field_array(proto_wol, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); +} + + +/* If this dissector uses sub-dissector registration add a registration routine. + This exact format is required because a script is used to find these + routines and create the code that calls these routines. + + This function is also called by preferences whenever "Apply" is pressed + (see prefs_register_protocol above) so it should accommodate being called + more than once. +*/ +void +proto_reg_handoff_wol(void) +{ + static gboolean inited = FALSE; + + if ( !inited ) + { + dissector_handle_t wol_handle; + +/* Use new_create_dissector_handle() to indicate that dissect_wol() + * returns the number of bytes it dissected (or 0 if it thinks the packet + * does not belong to PROTONAME). + */ + wol_handle = new_create_dissector_handle(dissect_wol, proto_wol); + + /* We don't really want to register with EVERY possible dissector, + * do we? I know that the AMD white paper specifies that the + * MagicPacket could be present in any frame, but are we seriously + * going to register WOL with every other dissector!? I think not. + * + * Unless anyone has a better idea, just register with only those that + * are in "common usage" and grow this list as needed. Yeah, I'm sure + * we'll miss some, but how else to do this ... add a thousand of + * these dissector_add()'s and heur_dissector_add()'s??? */ + dissector_add("ethertype", ETHERTYPE_WOL, wol_handle); + heur_dissector_add("udp", dissect_wol, proto_wol); + inited = TRUE; + } +} + diff --git a/epan/etypes.h b/epan/etypes.h index 1898b29c01..2a55e011f6 100644 --- a/epan/etypes.h +++ b/epan/etypes.h @@ -71,6 +71,10 @@ #define ETHERTYPE_ARP 0x0806 #endif +#ifndef ETHERTYPE_WOL +#define ETHERTYPE_WOL 0x0842 /* Wake on LAN. Not offically registered. */ +#endif + #ifndef ETHERTYPE_WMX_M2M #define ETHERTYPE_WMX_M2M 0x08f0 #endif -- cgit v1.2.3