File: __init__.py

package info (click to toggle)
python-wakeonlan 3.1.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 152 kB
  • sloc: python: 514; makefile: 7
file content (137 lines) | stat: -rwxr-xr-x 3,968 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env python3
"""
Small module for use with the wake on lan protocol.

"""
import argparse
import ipaddress
import socket
from typing import List
from typing import Optional


BROADCAST_IP = "255.255.255.255"
DEFAULT_PORT = 9


def create_magic_packet(macaddress: str) -> bytes:
    """
    Create a magic packet.

    A magic packet is a packet that can be used with the for wake on lan
    protocol to wake up a computer. The packet is constructed from the
    mac address given as a parameter.

    Args:
        macaddress: the mac address that should be parsed into a magic packet.

    """
    if len(macaddress) == 17:
        sep = macaddress[2]
        macaddress = macaddress.replace(sep, "")
    elif len(macaddress) == 14:
        sep = macaddress[4]
        macaddress = macaddress.replace(sep, "")
    if len(macaddress) != 12:
        raise ValueError("Incorrect MAC address format")
    return bytes.fromhex("F" * 12 + macaddress * 16)


def send_magic_packet(
    *macs: str,
    ip_address: str = BROADCAST_IP,
    port: int = DEFAULT_PORT,
    interface: Optional[str] = None,
    address_family: Optional[socket.AddressFamily] = None
) -> None:
    """
    Wake up computers having any of the given mac addresses.

    Wake on lan must be enabled on the host device.

    Args:
        macs: One or more macaddresses of machines to wake.

    Keyword Args:
        ip_address: the ip address of the host to send the magic packet to.
        port: the port of the host to send the magic packet to.
        interface: the ip address of the network adapter to route the magic packet through.
        address_family: the address family of the ip address to initiate connection with.
            When not specificied, chosen automatically between IPv4 and IPv6.

    """
    packets = [create_magic_packet(mac) for mac in macs]

    if address_family is None:
        address_family = (
            socket.AF_INET6 if _is_ipv6_address(ip_address) else socket.AF_INET
        )

    with socket.socket(address_family, socket.SOCK_DGRAM) as sock:
        if interface is not None:
            sock.bind((interface, 0))
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        sock.connect((ip_address, port))
        for packet in packets:
            sock.send(packet)


def _is_ipv6_address(ip_address: str) -> bool:
    try:
        return isinstance(ipaddress.ip_address(ip_address), ipaddress.IPv6Address)
    except ValueError:
        return False


def main(argv: Optional[List[str]] = None) -> None:
    """
    Run wake on lan as a CLI application.

    """
    parser = argparse.ArgumentParser(
        description="Wake one or more computers using the wake on lan protocol.",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )
    parser.add_argument(
        "macs",
        metavar="mac address",
        nargs="+",
        help="The mac addresses of the computers you are trying to wake.",
    )
    parser.add_argument(
        "-6",
        dest="use_ipv6",
        action="store_true",
        help="To indicate if ipv6 should be used by default instead of ipv4.",
    )
    parser.add_argument(
        "-i",
        metavar="ip",
        default=BROADCAST_IP,
        help="The ip address of the host to send the magic packet to.",
    )
    parser.add_argument(
        "-p",
        metavar="port",
        type=int,
        default=DEFAULT_PORT,
        help="The port of the host to send the magic packet to.",
    )
    parser.add_argument(
        "-n",
        metavar="interface",
        default=None,
        help="The ip address of the network adapter to route the magic packet through.",
    )
    args = parser.parse_args(argv)
    send_magic_packet(
        *args.macs,
        ip_address=args.i,
        port=args.p,
        interface=args.n,
        address_family=socket.AF_INET6 if args.use_ipv6 else None
    )


if __name__ == "__main__":  # pragma: nocover
    main()