Source code for univention.management.console.modules.computerroom.wakeonlan

#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# WakeOnLan/WOL helpers
#
# Copyright 2019-2025 Univention GmbH
#
# http://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <http://www.gnu.org/licenses/>.

from __future__ import absolute_import, print_function

import argparse
import socket
from typing import Iterable, Optional, Set  # noqa: F401

import netifaces

DEFAULT_PORT = 9


[docs] def get_local_ip_addresses(blacklisted_interfaces=None, blacklisted_interface_prefixes=None): # type: (Optional[Iterable[str]], Optional[Iterable[str]]) -> Set[str] """ Returns a list of local IPv4 addresses. :param blacklisted_interfaces: iterable that returns a list of interface names that shall be ignored :type blacklisted_interfaces: None or Iterable[str] :param blacklisted_interface_prefixes: iterable that returns a list of interface prefixes that shall be ignored :type blacklisted_interface_prefixes: None or Iterable[str] :return: list of IPv4 addresses :rtype: Set[str] """ result = set() # type: Set[str] for interface_name in netifaces.interfaces(): if blacklisted_interfaces is not None and interface_name in blacklisted_interfaces: continue if blacklisted_interface_prefixes is not None and any( interface_name.startswith(prefix) for prefix in blacklisted_interface_prefixes ): continue iface_info = netifaces.ifaddresses(interface_name) af_inet_addr = iface_info.get(netifaces.AF_INET, [{}])[0].get("addr") if af_inet_addr is not None: result.add(af_inet_addr) return result
[docs] def send_wol_packet( mac_address, blacklisted_interfaces=None, blacklisted_interface_prefixes=None, target_broadcast_ips=["255.255.255.255"], ): # type: (str, Optional[Iterable[str]], Optional[Iterable[str]], Optional[Iterable[str]]) -> None """ Sends a WakeOnLan packet to the specified MAC address via all interfaces (that are not blacklisted). >>> send_wol_packet( ... '12:34:56:78:9A:BC', ... blacklisted_interfaces=['lo'], ... blacklisted_interface_prefixes=['tun', 'docker']) >>> :param mac_address: MAC address of the target host :type mac_address: str :param blacklisted_interfaces: iterable that returns a list of interface names that shall be ignored :type blacklisted_interfaces: None or Iterable[str] :param blacklisted_interface_prefixes: iterable that returns a list of interface prefixes that shall be ignored :type blacklisted_interface_prefixes: None or Iterable[str] :param target_broadcast_ips: iterable that returns a list of target nets which are used for broadcasting :type target_broadcast_ips: None or Iterable[str] """ # remove usual delimiter characters addr = mac_address for c in ".:-": addr = addr.replace(c, "") # check MAC address validity if len(addr) != 12: raise ValueError("Invalid MAC address specified: {}".format(mac_address)) try: bytearray.fromhex(addr) except ValueError as exc: raise ValueError("Invalid MAC address specified: {}: {}".format(mac_address, exc)) # generate payload payload_hex = "FFFFFFFFFFFF" + (addr * 16) payload = bytes(bytearray.fromhex(payload_hex)) for local_addr in get_local_ip_addresses(blacklisted_interfaces, blacklisted_interface_prefixes): for ip in target_broadcast_ips: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) sock.bind((local_addr, 0)) sock.connect((ip, DEFAULT_PORT)) sock.send(payload) sock.close()
if __name__ == "__main__": desc = ( "console tool for sending wake-on-LAN (WOL) magic packets. Example: %(prog)s" " 11:22:33:44:55:66 -b lo wlan0 -p docker tun" ) parser = argparse.ArgumentParser(description=desc) parser.add_argument( "mac_address", metavar="MAC", type=str, help="a MAC address (e.g. 11:22:33:44:55:66)" ) parser.add_argument( "-b", "--blacklisted-interface", dest="blacklisted_interfaces", action="store", metavar="INTERFACE", type=str, nargs="+", help='list of blacklisted network interfaces (e.g. "lo wlan0")', ) parser.add_argument( "-p", "--blacklisted-interface-prefix", dest="blacklisted_interface_prefixes", action="store", metavar="INTERFACE", type=str, nargs="+", help='list of blacklisted network interface prefixes (e.g. "tun docker")', ) parser.add_argument( "-t", "--target-broadcast-ips", dest="target_broadcast_ips", action="store", metavar="INTERFACE", type=str, nargs="*", help="list of target broadcast-ips", default=["255.255.255.255"], ) args = parser.parse_args() print(repr(args)) send_wol_packet( args.mac_address, blacklisted_interfaces=args.blacklisted_interfaces, blacklisted_interface_prefixes=args.blacklisted_interface_prefixes, target_broadcast_ips=args.target_broadcast_ips, )