source: freewrt/package/ether-wake/files/ether-wake.c

freewrt_2_0
Last change on this file was 475ad56, checked in by Waldemar Brodkorb <wbx@…>, 20 years ago

add OpenWrt trunk revision 3830.

git-svn-id: svn://www.freewrt.org/trunk/freewrt@1 afb5a338-a214-0410-bd46-81f09a774fd1

  • Property mode set to 100644
File size: 10.8 KB
Line 
1/* ether-wake.c: Send a magic packet to wake up sleeping machines. */
2
3static char version_msg[] =
4"ether-wake.c: v1.09 11/12/2003 Donald Becker, http://www.scyld.com/";
5static char brief_usage_msg[] =
6"usage: ether-wake [-i <ifname>] [-p aa:bb:cc:dd[:ee:ff]] 00:11:22:33:44:55\n"
7" Use '-u' to see the complete set of options.\n";
8static char usage_msg[] =
9"usage: ether-wake [-i <ifname>] [-p aa:bb:cc:dd[:ee:ff]] 00:11:22:33:44:55\n"
10"\n"
11" This program generates and transmits a Wake-On-LAN (WOL)\n"
12" \"Magic Packet\", used for restarting machines that have been\n"
13" soft-powered-down (ACPI D3-warm state).\n"
14" It currently generates the standard AMD Magic Packet format, with\n"
15" an optional password appended.\n"
16"\n"
17" The single required parameter is the Ethernet MAC (station) address\n"
18" of the machine to wake or a host ID with known NSS 'ethers' entry.\n"
19" The MAC address may be found with the 'arp' program while the target\n"
20" machine is awake.\n"
21"\n"
22" Options:\n"
23" -b Send wake-up packet to the broadcast address.\n"
24" -D Increase the debug level.\n"
25" -i ifname Use interface IFNAME instead of the default 'eth0'.\n"
26" -p <pw> Append the four or six byte password PW to the packet.\n"
27" A password is only required for a few adapter types.\n"
28" The password may be specified in ethernet hex format\n"
29" or dotted decimal (Internet address)\n"
30" -p 00:22:44:66:88:aa\n"
31" -p 192.168.1.1\n";
32
33/*
34 This program generates and transmits a Wake-On-LAN (WOL) "Magic Packet",
35 used for restarting machines that have been soft-powered-down
36 (ACPI D3-warm state). It currently generates the standard AMD Magic Packet
37 format, with an optional password appended.
38
39 This software may be used and distributed according to the terms
40 of the GNU Public License, incorporated herein by reference.
41 Contact the author for use under other terms.
42
43 This source file was originally part of the network tricks package, and
44 is now distributed to support the Scyld Beowulf system.
45 Copyright 1999-2003 Donald Becker and Scyld Computing Corporation.
46
47 The author may be reached as becker@scyld, or C/O
48 Scyld Computing Corporation
49 914 Bay Ridge Road, Suite 220
50 Annapolis MD 21403
51
52 Notes:
53 On some systems dropping root capability allows the process to be
54 dumped, traced or debugged.
55 If someone traces this program, they get control of a raw socket.
56 Linux handles this safely, but beware when porting this program.
57
58 An alternative to needing 'root' is using a UDP broadcast socket, however
59 doing so only works with adapters configured for unicast+broadcast Rx
60 filter. That configuration consumes more power.
61*/
62
63
64#include <unistd.h>
65#include <stdlib.h>
66#include <stdio.h>
67#include <errno.h>
68#include <ctype.h>
69#include <string.h>
70
71#if 0 /* Only exists on some versions. */
72#include <ioctls.h>
73#endif
74
75#include <sys/socket.h>
76
77#include <sys/types.h>
78#include <sys/ioctl.h>
79#include <linux/if.h>
80
81#include <features.h>
82#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
83#include <netpacket/packet.h>
84#include <net/ethernet.h>
85#else
86#include <asm/types.h>
87#include <linux/if_packet.h>
88#include <linux/if_ether.h>
89#endif
90#include <netdb.h>
91#include <netinet/ether.h>
92
93/* Grrr, no consistency between include versions.
94 Enable this if setsockopt() isn't declared with your library. */
95#if 0
96extern int setsockopt __P ((int __fd, int __level, int __optname,
97 __ptr_t __optval, int __optlen));
98#else /* New, correct head files. */
99#include <sys/socket.h>
100#endif
101
102u_char outpack[1000];
103int outpack_sz = 0;
104int debug = 0;
105u_char wol_passwd[6];
106int wol_passwd_sz = 0;
107
108static int opt_no_src_addr = 0, opt_broadcast = 0;
109
110static int get_dest_addr(const char *arg, struct ether_addr *eaddr);
111static int get_fill(unsigned char *pkt, struct ether_addr *eaddr);
112static int get_wol_pw(const char *optarg);
113
114int main(int argc, char *argv[])
115{
116 char *ifname = "eth0";
117 int one = 1; /* True, for socket options. */
118 int s; /* Raw socket */
119 int errflag = 0, verbose = 0, do_version = 0;
120 int perm_failure = 0;
121 int i, c, pktsize;
122#if defined(PF_PACKET)
123 struct sockaddr_ll whereto;
124#else
125 struct sockaddr whereto; /* who to wake up */
126#endif
127 struct ether_addr eaddr;
128
129 while ((c = getopt(argc, argv, "bDi:p:uvV")) != -1)
130 switch (c) {
131 case 'b': opt_broadcast++; break;
132 case 'D': debug++; break;
133 case 'i': ifname = optarg; break;
134 case 'p': get_wol_pw(optarg); break;
135 case 'u': printf(usage_msg); return 0;
136 case 'v': verbose++; break;
137 case 'V': do_version++; break;
138 case '?':
139 errflag++;
140 }
141 if (verbose || do_version)
142 printf("%s\n", version_msg);
143 if (errflag) {
144 fprintf(stderr, brief_usage_msg);
145 return 3;
146 }
147
148 if (optind == argc) {
149 fprintf(stderr, "Specify the Ethernet address as 00:11:22:33:44:55.\n");
150 return 3;
151 }
152
153 /* Note: PF_INET, SOCK_DGRAM, IPPROTO_UDP would allow SIOCGIFHWADDR to
154 work as non-root, but we need SOCK_PACKET to specify the Ethernet
155 destination address. */
156#if defined(PF_PACKET)
157 s = socket(PF_PACKET, SOCK_RAW, 0);
158#else
159 s = socket(AF_INET, SOCK_PACKET, SOCK_PACKET);
160#endif
161 if (s < 0) {
162 if (errno == EPERM)
163 fprintf(stderr, "ether-wake: This program must be run as root.\n");
164 else
165 perror("ether-wake: socket");
166 perm_failure++;
167 }
168 /* Don't revert if debugging allows a normal user to get the raw socket. */
169 setuid(getuid());
170
171 /* We look up the station address before reporting failure so that
172 errors may be reported even when run as a normal user.
173 */
174 if (get_dest_addr(argv[optind], &eaddr) != 0)
175 return 3;
176 if (perm_failure && ! debug)
177 return 2;
178
179 pktsize = get_fill(outpack, &eaddr);
180
181 /* Fill in the source address, if possible.
182 The code to retrieve the local station address is Linux specific. */
183 if (! opt_no_src_addr) {
184 struct ifreq if_hwaddr;
185 unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data;
186
187 strcpy(if_hwaddr.ifr_name, ifname);
188 if (ioctl(s, SIOCGIFHWADDR, &if_hwaddr) < 0) {
189 fprintf(stderr, "SIOCGIFHWADDR on %s failed: %s\n", ifname,
190 strerror(errno));
191 /* Magic packets still work if our source address is bogus, but
192 we fail just to be anal. */
193 return 1;
194 }
195 memcpy(outpack+6, if_hwaddr.ifr_hwaddr.sa_data, 6);
196
197 if (verbose) {
198 printf("The hardware address (SIOCGIFHWADDR) of %s is type %d "
199 "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", ifname,
200 if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1],
201 hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
202 }
203 }
204
205 if (wol_passwd_sz > 0) {
206 memcpy(outpack+pktsize, wol_passwd, wol_passwd_sz);
207 pktsize += wol_passwd_sz;
208 }
209
210 if (verbose > 1) {
211 printf("The final packet is: ");
212 for (i = 0; i < pktsize; i++)
213 printf(" %2.2x", outpack[i]);
214 printf(".\n");
215 }
216
217 /* This is necessary for broadcasts to work */
218 if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&one, sizeof(one)) < 0)
219 perror("setsockopt: SO_BROADCAST");
220
221#if defined(PF_PACKET)
222 {
223 struct ifreq ifr;
224 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
225 if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) {
226 fprintf(stderr, "SIOCGIFINDEX on %s failed: %s\n", ifname,
227 strerror(errno));
228 return 1;
229 }
230 memset(&whereto, 0, sizeof(whereto));
231 whereto.sll_family = AF_PACKET;
232 whereto.sll_ifindex = ifr.ifr_ifindex;
233 /* The manual page incorrectly claims the address must be filled.
234 We do so because the code may change to match the docs. */
235 whereto.sll_halen = ETH_ALEN;
236 memcpy(whereto.sll_addr, outpack, ETH_ALEN);
237
238 }
239#else
240 whereto.sa_family = 0;
241 strcpy(whereto.sa_data, ifname);
242#endif
243
244 if ((i = sendto(s, outpack, pktsize, 0, (struct sockaddr *)&whereto,
245 sizeof(whereto))) < 0)
246 perror("sendto");
247 else if (debug)
248 printf("Sendto worked ! %d.\n", i);
249
250#ifdef USE_SEND
251 if (bind(s, (struct sockaddr *)&whereto, sizeof(whereto)) < 0)
252 perror("bind");
253 else if (send(s, outpack, 100, 0) < 0)
254 perror("send");
255#endif
256#ifdef USE_SENDMSG
257 {
258 struct msghdr msghdr = { 0,};
259 struct iovec iovector[1];
260 msghdr.msg_name = &whereto;
261 msghdr.msg_namelen = sizeof(whereto);
262 msghdr.msg_iov = iovector;
263 msghdr.msg_iovlen = 1;
264 iovector[0].iov_base = outpack;
265 iovector[0].iov_len = pktsize;
266 if ((i = sendmsg(s, &msghdr, 0)) < 0)
267 perror("sendmsg");
268 else if (debug)
269 printf("sendmsg worked, %d (%d).\n", i, errno);
270 }
271#endif
272
273 return 0;
274}
275
276/* Convert the host ID string to a MAC address.
277 The string may be a
278 Host name
279 IP address string
280 MAC address string
281*/
282
283static int get_dest_addr(const char *hostid, struct ether_addr *eaddr)
284{
285 struct ether_addr *eap;
286
287 eap = ether_aton(hostid);
288 if (eap) {
289 *eaddr = *eap;
290 if (debug)
291 fprintf(stderr, "The target station address is %s.\n",
292 ether_ntoa(eaddr));
293 } else if (ether_hostton(hostid, eaddr) == 0) {
294 if (debug)
295 fprintf(stderr, "Station address for hostname %s is %s.\n",
296 hostid, ether_ntoa(eaddr));
297 } else {
298 (void)fprintf(stderr,
299 "ether-wake: The Magic Packet host address must be "
300 "specified as\n"
301 " - a station address, 00:11:22:33:44:55, or\n"
302 " - a hostname with a known 'ethers' entry.\n");
303 return -1;
304 }
305 return 0;
306}
307
308
309static int get_fill(unsigned char *pkt, struct ether_addr *eaddr)
310{
311 int offset, i;
312 unsigned char *station_addr = eaddr->ether_addr_octet;
313
314 if (opt_broadcast)
315 memset(pkt+0, 0xff, 6);
316 else
317 memcpy(pkt, station_addr, 6);
318 memcpy(pkt+6, station_addr, 6);
319 pkt[12] = 0x08; /* Or 0x0806 for ARP, 0x8035 for RARP */
320 pkt[13] = 0x42;
321 offset = 14;
322
323 memset(pkt+offset, 0xff, 6);
324 offset += 6;
325
326 for (i = 0; i < 16; i++) {
327 memcpy(pkt+offset, station_addr, 6);
328 offset += 6;
329 }
330 if (debug) {
331 fprintf(stderr, "Packet is ");
332 for (i = 0; i < offset; i++)
333 fprintf(stderr, " %2.2x", pkt[i]);
334 fprintf(stderr, ".\n");
335 }
336 return offset;
337}
338
339static int get_wol_pw(const char *optarg)
340{
341 int passwd[6];
342 int byte_cnt;
343 int i;
344
345 byte_cnt = sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x",
346 &passwd[0], &passwd[1], &passwd[2],
347 &passwd[3], &passwd[4], &passwd[5]);
348 if (byte_cnt < 4)
349 byte_cnt = sscanf(optarg, "%d.%d.%d.%d",
350 &passwd[0], &passwd[1], &passwd[2], &passwd[3]);
351 if (byte_cnt < 4) {
352 fprintf(stderr, "Unable to read the Wake-On-LAN password.\n");
353 return 0;
354 }
355 printf(" The Magic packet password is %2.2x %2.2x %2.2x %2.2x (%d).\n",
356 passwd[0], passwd[1], passwd[2], passwd[3], byte_cnt);
357 for (i = 0; i < byte_cnt; i++)
358 wol_passwd[i] = passwd[i];
359 return wol_passwd_sz = byte_cnt;
360}
361
362#if 0
363{
364 to = (struct sockaddr_in *)&whereto;
365 to->sin_family = AF_INET;
366 if (inet_aton(target, &to->sin_addr)) {
367 hostname = target;
368 }
369 memset (&sa, 0, sizeof sa);
370 sa.sa_family = AF_INET;
371 strncpy (sa.sa_data, interface, sizeof sa.sa_data);
372 sendto (sock, buf, bufix + len, 0, &sa, sizeof sa);
373 strncpy (sa.sa_data, interface, sizeof sa.sa_data);
374#if 1
375 sendto (sock, buf, bufix + len, 0, &sa, sizeof sa);
376#else
377 bind (sock, &sa, sizeof sa);
378 connect();
379 send (sock, buf, bufix + len, 0);
380#endif
381}
382#endif
383
384
385
386/*
387 * Local variables:
388 * compile-command: "gcc -O -Wall -o ether-wake ether-wake.c"
389 * c-indent-level: 4
390 * c-basic-offset: 4
391 * c-indent-level: 4
392 * tab-width: 4
393 * End:
394 */
Note: See TracBrowser for help on using the repository browser.