diff --git a/README.rst b/README.rst index 319b849..f2e5e43 100644 --- a/README.rst +++ b/README.rst @@ -65,22 +65,29 @@ required. The default ip address is 255.255.255.255 and the default port is 9. ... port=1337) +A network adapter may be specified. The magic packet will be routed through this interface. + +>>> send_magic_packet('ff.ff.ff.ff.ff.ff', +... interface='192.168.0.2') + + As a standalone script ====================== :: - usage: wakeonlan [-h] [-i ip] [-p port] mac address [mac address ...] + usage: wakeonlan [-h] [-i ip] [-p port] [-n interface] mac address [mac address ...] Wake one or more computers using the wake on lan protocol. positional arguments: - mac address The mac addresses or of the computers you are trying to wake. + mac address The mac addresses of the computers you are trying to wake. optional arguments: -h, --help show this help message and exit -i ip The ip address of the host to send the magic packet to. (default 255.255.255.255) -p port The port of the host to send the magic packet to. (default 9) + -n interface The ip address of the network adapter to route the magic packet through. (optional) ************ diff --git a/test_wakeonlan.py b/test_wakeonlan.py index 53f441f..dda8574 100644 --- a/test_wakeonlan.py +++ b/test_wakeonlan.py @@ -208,6 +208,71 @@ def test_send_magic_packet_default(sock: Mock) -> None: ] +@patch("socket.socket") +def test_send_magic_packet_interface(sock: Mock) -> None: + """ + Test whether the magic packets are broadcasted to the specified network via specified interface. + + """ + send_magic_packet( + "133713371337", + "00-00-00-00-00-00", + ip_address="example.com", + port=7, + interface="192.168.0.2", + ) + assert sock.mock_calls == [ + call(socket.AF_INET, socket.SOCK_DGRAM), + call().__enter__(), + call().__enter__().bind(("192.168.0.2", 0)), + call().__enter__().setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1), + call().__enter__().connect(("example.com", 7)), + call() + .__enter__() + .send( + b"\xff\xff\xff\xff\xff\xff" + b"\x137\x137\x137" + b"\x137\x137\x137" + b"\x137\x137\x137" + b"\x137\x137\x137" + b"\x137\x137\x137" + b"\x137\x137\x137" + b"\x137\x137\x137" + b"\x137\x137\x137" + b"\x137\x137\x137" + b"\x137\x137\x137" + b"\x137\x137\x137" + b"\x137\x137\x137" + b"\x137\x137\x137" + b"\x137\x137\x137" + b"\x137\x137\x137" + b"\x137\x137\x137" + ), + call() + .__enter__() + .send( + b"\xff\xff\xff\xff\xff\xff" + b"\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00" + ), + call().__exit__(None, None, None), + ] + + @patch("wakeonlan.send_magic_packet") def test_main(send_magic_packet: Mock) -> None: """ @@ -215,6 +280,13 @@ def test_main(send_magic_packet: Mock) -> None: """ main(["00:11:22:33:44:55", "-i", "host.example", "-p", "1337"]) + main(["00:11:22:33:44:55", "-i", "host.example", "-p", "1337", "-n", "192.168.0.2"]) assert send_magic_packet.mock_calls == [ - call("00:11:22:33:44:55", ip_address="host.example", port=1337,) + call("00:11:22:33:44:55", ip_address="host.example", port=1337, interface=None), + call( + "00:11:22:33:44:55", + ip_address="host.example", + port=1337, + interface="192.168.0.2", + ), ] diff --git a/wakeonlan.py b/wakeonlan.py index 9d121e2..7ea2c66 100755 --- a/wakeonlan.py +++ b/wakeonlan.py @@ -34,7 +34,10 @@ def create_magic_packet(macaddress: str) -> bytes: def send_magic_packet( - *macs: str, ip_address: str = BROADCAST_IP, port: int = DEFAULT_PORT + *macs: str, + ip_address: str = BROADCAST_IP, + port: int = DEFAULT_PORT, + interface: str = None ) -> None: """ Wake up computers having any of the given mac addresses. @@ -47,11 +50,14 @@ def send_magic_packet( 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. """ packets = [create_magic_packet(mac) for mac in macs] with socket.socket(socket.AF_INET, 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: @@ -71,7 +77,7 @@ def main(argv: List[str] = None) -> None: "macs", metavar="mac address", nargs="+", - help="The mac addresses or of the computers you are trying to wake.", + help="The mac addresses of the computers you are trying to wake.", ) parser.add_argument( "-i", @@ -86,8 +92,14 @@ def main(argv: List[str] = None) -> None: 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) + send_magic_packet(*args.macs, ip_address=args.i, port=args.p, interface=args.n) if __name__ == "__main__": # pragma: nocover