From 062569a1113d1d8ddf2056934a6be59c7fda1270 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Mon, 20 Jan 2014 21:05:39 -0600 Subject: [PATCH] wakeonlan: Added Wake-on-LAN magic packet sender script --- wakeonlan.py | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100755 wakeonlan.py diff --git a/wakeonlan.py b/wakeonlan.py new file mode 100755 index 0000000..ac4b9e9 --- /dev/null +++ b/wakeonlan.py @@ -0,0 +1,99 @@ +#!/usr/bin/python +'''Send a Wake-on-LAN magic packet + +This program can be used to send a Wake-on-LAN magic packet to a host +on the local network. A WOL magic packet consists of 6 bytes of all +ones, followed by sixteen repetitions of the target system's hardware +(MAC) address. A WOL magic packet can be sent to any network (IP) +address, as the contents of the packet are only inspected for the +exact contents above, regardless of other header information. +Typically, magic packets are broadcast, either to the limited +broadcast address (255.255.255.255) or the network broadcast +address to ensure that routers and switches will forward them to +the desired destination host. + +:Author: Dustin C. Hatch +:Copyright: 2014 Dustin C. Hatch +:License: Apache 2.0 +''' + +import argparse +import re +import socket +import sys + + +def wake(mac_addr, ip_addr='255.255.255.255', port=9): + '''Send a Wake-on-LAN magic packet + + :param mac: Destination hardware (MAC) address + ''' + + # strip all formatting characters from the given + # address and convert it to an integer. + # this allows any formatting variant to be accepted, + # including: + # * standard: 00:11:22:aa:bb:cc + # * Windows: 00-11-22-AA-BB-CC + # * Cisco: 0011.22AA.BBCC + mac_int = int(re.sub('[^0-9a-f]', '', mac_addr.lower()), 16) + # separate the address into eight-bit pieces (as integers) + mac_intlist = [] + while mac_int > 0: + mac_intlist.insert(0, mac_int & 0xff) + mac_int >>= 8 + + # convert the 6 integers to a byte string + # and generate the preamble + if str is bytes: # Python 2 + payload = '\xff' * 6 + mac = ''.join(chr(b) for b in mac_intlist) + else: + payload = bytes((0xff,) * 6) + mac = bytes(mac_intlist) + + # populate the remainder of the packet payload by repeating + # the destination hardware address + for _ in range(16): + payload += mac + + # open a UDP-IP broadcast socket and send the packet + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + s.connect((ip_addr, port)) + s.send(payload) + s.close() + + +def _parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('-i', dest='ip_address', metavar='ADDRESS', + default='255.255.255.255', + help='destination IP address') + parser.add_argument('-p', dest='port', metavar='PORT', type=int, + default=9, help='destination UDP port') + parser.add_argument('-f', dest='macfile', metavar='FILE', + help='read destination hardware addresses from FILE') + parser.add_argument('address', help='destination hardware (MAC) address', + nargs='*') + args = parser.parse_args() + if not args.address and not args.macfile: + parser.error('No hardware address given') + return args + + +def main(): + args = _parse_args() + + if args.macfile: + with open(args.macfile) as f: + for line in f.readlines(): + # each address in the file can be followed by a comment + mac, _ = line.split(None, 1) + wake(mac, args.ip_address, args.port) + else: + for mac in args.address: + wake(mac, args.ip_address, args.port) + +if __name__ == '__main__': + main()