scripts/wakeonlan.py

100 lines
3.3 KiB
Python
Executable File

#!/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 <dustin@hatch.name>
: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()