From 45812fc4691b26d8701aeea41a2c349aaa623dbb Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Thu, 23 Jan 2025 14:29:57 +0100 Subject: [PATCH] calculate broadcast addr via ipaddress lib --- psutil/__init__.py | 13 ++++++++++++- psutil/_common.py | 19 +++++++++++++++++-- psutil/tests/test_system.py | 8 ++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/psutil/__init__.py b/psutil/__init__.py index 605138e22..6fd88b00f 100644 --- a/psutil/__init__.py +++ b/psutil/__init__.py @@ -2228,6 +2228,7 @@ def net_if_addrs(): # We re-set the family here so that repr(family) # will show AF_LINK rather than AF_PACKET fam = _psplatform.AF_LINK + if fam == _psplatform.AF_LINK: # The underlying C function may return an incomplete MAC # address in which case we fill it with null bytes, see: @@ -2235,7 +2236,17 @@ def net_if_addrs(): separator = ":" if POSIX else "-" while addr.count(separator) < 5: addr += f"{separator}00" - ret[name].append(_common.snicaddr(fam, addr, mask, broadcast, ptp)) + + nt = _common.snicaddr(fam, addr, mask, broadcast, ptp) + + # On Windows broadcast is None, so we determine it via + # ipaddress module. + if WINDOWS and fam in {socket.AF_INET, socket.AF_INET6}: + broadcast = _common.broadcast_addr(nt) + nt._replace(broadcast=broadcast) + + ret[name].append(nt) + return dict(ret) diff --git a/psutil/_common.py b/psutil/_common.py index 0c385fa6a..a0bb18b02 100644 --- a/psutil/_common.py +++ b/psutil/_common.py @@ -6,8 +6,6 @@ # Note: this module is imported by setup.py so it should not import # psutil or third-party modules. - - import collections import enum import functools @@ -603,6 +601,23 @@ def conn_to_ntuple(fd, fam, type_, laddr, raddr, status, status_map, pid=None): return sconn(fd, fam, type_, laddr, raddr, status, pid) +def broadcast_addr(addr): + import ipaddress + + if addr.family == socket.AF_INET: + return str( + ipaddress.IPv4Network( + f"{addr.address}/{addr.netmask}", strict=False + ).broadcast_address + ) + elif addr.family == socket.AF_INET6: + return str( + ipaddress.IPv6Network( + f"{addr.address}/{addr.netmask}", strict=False + ).broadcast_address + ) + + def deprecated_method(replacement): """A decorator which can be used to mark a method as deprecated 'replcement' is the method name which will be called instead. diff --git a/psutil/tests/test_system.py b/psutil/tests/test_system.py index e2efca149..aacc9fb0b 100755 --- a/psutil/tests/test_system.py +++ b/psutil/tests/test_system.py @@ -30,6 +30,7 @@ from psutil import POSIX from psutil import SUNOS from psutil import WINDOWS +from psutil._common import broadcast_addr from psutil.tests import ASCII_FS from psutil.tests import CI_TESTING from psutil.tests import GITHUB_ACTIONS @@ -858,6 +859,13 @@ def test_net_if_addrs(self): elif addr.ptp: assert addr.broadcast is None + # check broadcast address + if addr.broadcast and addr.family in { + socket.AF_INET, + socket.AF_INET6, + }: + assert addr.broadcast == broadcast_addr(addr) + if BSD or MACOS or SUNOS: if hasattr(socket, "AF_LINK"): assert psutil.AF_LINK == socket.AF_LINK