Coverage Report

Created: 2026-01-02 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-wol.c
Line
Count
Source
1
/* packet-wol.c
2
 * Routines for WOL dissection
3
 * Copyright 2007, Christopher Maynard <Chris.Maynard[AT]gtech.com>
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * This dissector for "Wake On LAN" was not copied from any other existing
10
 * dissector.  It uses the template from SVN23520 docs/README.devloper, which
11
 * was the latest one available at the time of this writing.  This dissector is
12
 * a heuristic one though, so appropriate changes have made to the template
13
 * as needed.
14
 *
15
 * The "Wake On LAN" dissector was written based primarily on the AMD white
16
 * paper, available from:
17
 *
18
 *    https://web.archive.org/web/20100601154907/http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/20213.pdf
19
 *
20
 * In addition, testing of the dissector was conducted using 2 utilities
21
 * downloaded from http://www.moldaner.de/wakeonlan/wakeonlan.html and
22
 * http://www.depicus.com/wake-on-lan/, as well as with the ether-wake utility
23
 * on a Linux Fedora Core 4 system.
24
 *
25
 * From what I can tell from the tools available, even though the white paper
26
 * indicates that the so-called, "MagicPacket" can be located anywhere within
27
 * the Ethernet frame, in practice, there seem to be only 2 variations of the
28
 * implementation of the MagicPacket.  Ether-wake implements it as an Ethernet
29
 * frame with ether type 0x0842 (ETHERTYPE_WOL), and the other tools all seem
30
 * to implement it as a UDP packet, both with the payload as nothing but the
31
 * MagicPacket.
32
 *
33
 * To keep things simple, this dissector will only indicate a frame as
34
 * Wake-On-Lan if the MagicPacket is found for a frame marked as etherytpe
35
 * 0x0842 or if it's a UDP packet.  To fully support Wake-On-Lan dissection
36
 * though, we would need a way to have this dissector called only if the frame
37
 * hasn't already been classified as some other type of dissector ... but I
38
 * don't know how to do that?  The only alternative I am aware of would be to
39
 * register as a heuristic dissector for pretty much every possible protocol
40
 * there is, which seems unreasonable to do to me.
41
 *
42
 * SPDX-License-Identifier: GPL-2.0-or-later
43
 */
44
45
#include "config.h"
46
47
#include <epan/packet.h>
48
#include <epan/addr_resolv.h>
49
#include <epan/etypes.h>
50
51
void proto_register_wol(void);
52
void proto_reg_handoff_wol(void);
53
54
static dissector_handle_t wol_handle;
55
56
/* Initialize the protocol and registered fields */
57
static int proto_wol;
58
static int hf_wol_sync;
59
static int hf_wol_mac;
60
static int hf_wol_passwd;
61
62
/* Initialize the subtree pointers */
63
static int ett_wol;
64
static int ett_wol_macblock;
65
66
/* Code to actually dissect the packets */
67
static int
68
dissect_wol_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
69
1.57k
{
70
1.57k
    unsigned      len;
71
1.57k
    int           offset;
72
1.57k
    uint8_t      *mac;
73
1.57k
    const uint8_t *passwd;
74
1.57k
    uint64_t      qword;
75
1.57k
    address      mac_addr;
76
77
/* Set up structures needed to add the protocol subtree and manage it */
78
1.57k
    proto_item *ti;
79
1.57k
    proto_tree *wol_tree;
80
1.57k
    proto_tree *mac_tree;
81
82
/*  First, if at all possible, do some heuristics to check if the packet cannot
83
 *  possibly belong to your protocol.  This is especially important for
84
 *  protocols directly on top of TCP or UDP where port collisions are
85
 *  common place (e.g., even though your protocol uses a well known port,
86
 *  someone else may set up, for example, a web server on that port which,
87
 *  if someone analyzed that web server's traffic in Wireshark, would result
88
 *  in Wireshark handing an HTTP packet to your dissector).  For example:
89
 */
90
    /* Check that there's enough data */
91
1.57k
    len = tvb_reported_length(tvb);
92
1.57k
    if ( len < 102 )    /* wol's smallest packet size is 102 */
93
1.29k
        return 0;
94
95
    /* Get some values from the packet header, probably using tvb_get_*() */
96
97
    /* Regardless of what the AMD white paper states, don't search the entire
98
     * tvb for the synchronization stream.  My feeling is that this could be
99
     * quite expensive and seriously hinder Wireshark performance.  For now,
100
     * unless we need to change it later, just compare the 1st 6 bytes. */
101
283
    qword = tvb_get_ntoh48(tvb,0);
102
283
    if(qword != UINT64_C(0xffffffffffff))
103
261
        return 0;
104
105
    /* So far so good.  Now get the next 6 bytes, which we'll assume is the
106
     * target's MAC address, and do 15 memory chunk comparisons, since if this
107
     * is a real MagicPacket, the target's MAC will be duplicated 16 times. */
108
22
    mac = (uint8_t *)tvb_memdup(pinfo->pool, tvb, 6, 6);
109
210
    for ( offset = 12; offset < 102; offset += 6 )
110
205
        if ( tvb_memeql(tvb, offset, mac, 6) != 0 )
111
17
            return 0;
112
113
    /* OK, we're going to assume it's a MagicPacket.  If there's a password,
114
     * grab it now, and in case there's any extra bytes after the only 3 valid
115
     * and expected lengths, truncate the length so the extra byte(s) aren't
116
     * included as being part of the WOL payload. */
117
5
    if ( len >= 106 && len < 108 )
118
1
    {
119
1
        len = 106;
120
1
        passwd = (uint8_t*)tvb_ip_to_str(pinfo->pool, tvb, 102);
121
1
    }
122
4
    else if ( len >= 108 )
123
3
    {
124
3
        len = 108;
125
3
        passwd = (uint8_t*)tvb_ether_to_str(pinfo->pool, tvb, 102);
126
3
    }
127
1
    else
128
1
    {
129
1
        len = 102;
130
1
        passwd = NULL;
131
1
    }
132
133
/* Make entries in Protocol column and Info column on summary display */
134
5
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "WOL");
135
136
/* This field shows up as the "Info" column in the display; you should use
137
   it, if possible, to summarize what's in the packet, so that a user looking
138
   at the list of packets can tell what type of packet it is. See section 1.5
139
   for more information.
140
141
   If you are setting the column to a constant string, use "col_set_str()",
142
   as it's more efficient than the other "col_set_XXX()" calls.
143
144
   If you're setting it to a string you've constructed, or will be
145
   appending to the column later, use "col_add_str()".
146
147
   "col_add_fstr()" can be used instead of "col_add_str()"; it takes
148
   "printf()"-like arguments.  Don't use "col_add_fstr()" with a format
149
   string of "%s" - just use "col_add_str()" or "col_set_str()", as it's
150
   more efficient than "col_add_fstr()".
151
152
   If you will be fetching any data from the packet before filling in
153
   the Info column, clear that column first, in case the calls to fetch
154
   data from the packet throw an exception because they're fetching data
155
   past the end of the packet, so that the Info column doesn't have data
156
   left over from the previous dissector; do
157
158
    col_clear(pinfo->cinfo, COL_INFO);
159
160
   */
161
5
    set_address(&mac_addr, AT_ETHER, 6, mac);
162
163
5
    col_add_fstr(pinfo->cinfo, COL_INFO, "MagicPacket for %s",
164
5
        address_with_resolution_to_str(pinfo->pool, &mac_addr));
165
166
    /* NOTE: ether-wake uses a dotted-decimal format for specifying a
167
        * 4-byte password or an Ethernet mac address format for specifying
168
        * a 6-byte password, so display them in that format, even if the
169
        * password isn't really an IP or MAC address. */
170
5
    if ( passwd )
171
4
        col_append_fstr(pinfo->cinfo, COL_INFO, ", password %s", passwd);
172
173
/* A protocol dissector can be called in 2 different ways:
174
175
    (a) Operational dissection
176
177
        In this mode, Wireshark is only interested in the way protocols
178
        interact, protocol conversations are created, packets are
179
        reassembled and handed over to higher-level protocol dissectors.
180
        In this mode Wireshark does not build a so-called "protocol
181
        tree".
182
183
    (b) Detailed dissection
184
185
        In this mode, Wireshark is also interested in all details of
186
        a given protocol, so a "protocol tree" is created.
187
188
   Wireshark distinguishes between the 2 modes with the proto_tree pointer:
189
    (a) <=> tree == NULL
190
    (b) <=> tree != NULL
191
192
   In the interest of speed, if "tree" is NULL, avoid building a
193
   protocol tree and adding stuff to it, or even looking at any packet
194
   data needed only if you're building the protocol tree, if possible.
195
196
   Note, however, that you must fill in column information, create
197
   conversations, reassemble packets, build any other persistent state
198
   needed for dissection, and call subdissectors regardless of whether
199
   "tree" is NULL or not.  This might be inconvenient to do without
200
   doing most of the dissection work; the routines for adding items to
201
   the protocol tree can be passed a null protocol tree pointer, in
202
   which case they'll return a null item pointer, and
203
   "proto_item_add_subtree()" returns a null tree pointer if passed a
204
   null item pointer, so, if you're careful not to dereference any null
205
   tree or item pointers, you can accomplish this by doing all the
206
   dissection work.  This might not be as efficient as skipping that
207
   work if you're not building a protocol tree, but if the code would
208
   have a lot of tests whether "tree" is null if you skipped that work,
209
   you might still be better off just doing all that work regardless of
210
   whether "tree" is null or not. */
211
5
    if (tree) {
212
213
/* NOTE: The offset and length values in the call to
214
   "proto_tree_add_item()" define what data bytes to highlight in the hex
215
   display window when the line in the protocol tree display
216
   corresponding to that item is selected.
217
218
   Supplying a length of -1 is the way to highlight all data from the
219
   offset to the end of the packet. */
220
221
/* create display subtree for the protocol */
222
5
        ti = proto_tree_add_item(tree, proto_wol, tvb, 0, len, ENC_NA);
223
5
        proto_item_append_text(ti, ", MAC: %s",
224
5
            address_with_resolution_to_str(pinfo->pool, &mac_addr));
225
5
        if ( passwd )
226
4
            proto_item_append_text(ti, ", password: %s", passwd);
227
5
        wol_tree = proto_item_add_subtree(ti, ett_wol);
228
229
/* add an item to the subtree, see section 1.6 for more information */
230
5
        proto_tree_add_item(wol_tree, hf_wol_sync, tvb, 0, 6, ENC_NA);
231
232
/* Continue adding tree items to process the packet here */
233
5
        mac_tree = proto_tree_add_subtree_format(wol_tree, tvb, 6, 96,
234
5
            ett_wol_macblock, NULL, "MAC: %s",
235
5
            address_with_resolution_to_str(pinfo->pool, &mac_addr));
236
85
        for ( offset = 6; offset < 102; offset += 6 )
237
80
            proto_tree_add_ether(mac_tree, hf_wol_mac, tvb, offset, 6, mac);
238
239
5
        if ( len == 106 )
240
1
            proto_tree_add_bytes_format_value(wol_tree, hf_wol_passwd, tvb, offset,
241
1
                4, passwd, "%s", passwd);
242
4
        else if ( len == 108 )
243
3
            proto_tree_add_bytes_format_value(wol_tree, hf_wol_passwd, tvb, offset,
244
3
                6, passwd, "%s", passwd);
245
5
    }
246
247
5
    return (len);
248
22
}
249
250
static int
251
dissect_wol(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
252
10
{
253
10
    return dissect_wol_pdu(tvb, pinfo, tree, data);
254
10
}
255
256
static bool
257
dissect_wolheur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
258
1.56k
{
259
1.56k
    if (dissect_wol_pdu(tvb, pinfo, tree, data) > 0)
260
3
        return true;
261
262
1.56k
    return false;
263
1.56k
}
264
265
266
/* Register the protocol with Wireshark */
267
268
/* this format is require because a script is used to build the C function
269
   that calls all the protocol registration.
270
*/
271
272
void
273
proto_register_wol(void)
274
14
{
275
/* Setup list of header fields  See Section 1.6.1 for details*/
276
14
    static hf_register_info hf[] = {
277
14
        { &hf_wol_sync,
278
14
            { "Sync stream", "wol.sync",
279
14
            FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
280
14
        { &hf_wol_mac,
281
14
            { "MAC", "wol.mac",
282
14
            FT_ETHER, BASE_NONE, NULL, 0, NULL, HFILL }},
283
14
        { &hf_wol_passwd,
284
14
            { "Password", "wol.passwd",
285
14
            FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }}
286
14
    };
287
288
/* Setup protocol subtree array */
289
14
    static int *ett[] = {
290
14
        &ett_wol,
291
14
        &ett_wol_macblock
292
14
    };
293
294
/* Register the protocol name and description */
295
14
    proto_wol = proto_register_protocol("Wake On LAN", "WOL", "wol");
296
297
/* Required function calls to register the header fields and subtrees used */
298
14
    proto_register_field_array(proto_wol, hf, array_length(hf));
299
14
    proto_register_subtree_array(ett, array_length(ett));
300
301
/* Register our dissector handle */
302
14
    wol_handle = register_dissector("wol", dissect_wol, proto_wol);
303
14
}
304
305
/* If this dissector uses sub-dissector registration add a registration routine.
306
   This exact format is required because a script is used to find these
307
   routines and create the code that calls these routines.
308
309
*/
310
void
311
proto_reg_handoff_wol(void)
312
14
{
313
    /* We don't really want to register with EVERY possible dissector,
314
     * do we?  I know that the AMD white paper specifies that the
315
     * MagicPacket could be present in any frame, but are we seriously
316
     * going to register WOL with every other dissector!?  I think not.
317
     *
318
     * Unless anyone has a better idea, just register with only those that
319
     * are in "common usage" and grow this list as needed.  Yeah, I'm sure
320
     * we'll miss some, but how else to do this ... add a thousand of
321
     * these dissector_add_uint()'s and heur_dissector_add()'s??? */
322
14
    dissector_add_uint("ethertype", ETHERTYPE_WOL, wol_handle);
323
14
    heur_dissector_add("udp", dissect_wolheur, "Wake On LAN over UDP", "wol_udp", proto_wol, HEURISTIC_ENABLE);
324
14
}
325
326
/*
327
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
328
 *
329
 * Local variables:
330
 * c-basic-offset: 4
331
 * tab-width: 8
332
 * indent-tabs-mode: nil
333
 * End:
334
 *
335
 * vi: set shiftwidth=4 tabstop=8 expandtab:
336
 * :indentSize=4:tabSize=8:noTabs=true:
337
 */