/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 | | */ |