Files
dotfiles/config/ansible/tasks/global/utils/ipaddr
Menno van Leeuwen 4aee9266d5
Some checks failed
Ansible Lint Check / check-ansible (push) Failing after 14s
Nix Format Check / check-format (push) Successful in 1m18s
Python Lint Check / check-python (push) Failing after 11s
feat: add utility tasks for making custom utilities available in ~/.local/bin
2025-03-26 13:56:43 +01:00

125 lines
4.8 KiB
Python
Executable File

#!/usr/bin/env python3
import os
import subprocess
import argparse
def get_physical_interfaces():
"""
Retrieve a list of physical network interfaces on the system.
This function checks the `/sys/class/net/` directory to identify physical
network interfaces. It determines if an interface is physical by verifying
the presence of a symbolic link to a `device` directory.
Returns:
list: A list of strings, where each string is the name of a physical
network interface.
"""
interfaces_path = '/sys/class/net/'
physical_interfaces = []
for interface in os.listdir(interfaces_path):
if not os.path.islink(os.path.join(interfaces_path, interface, 'device')):
continue
physical_interfaces.append(interface)
return physical_interfaces
def get_virtual_interfaces():
"""
Retrieves a list of virtual network interfaces on the system.
This function scans the network interfaces available in the '/sys/class/net/'
directory and filters out physical interfaces and the loopback interface ('lo').
It identifies virtual interfaces by checking if the 'device' path is not a
symbolic link.
Returns:
list: A list of virtual network interface names as strings.
"""
interfaces_path = '/sys/class/net/'
virtual_interfaces = []
for interface in os.listdir(interfaces_path):
if os.path.islink(os.path.join(interfaces_path, interface, 'device')):
continue
if interface == 'lo':
continue
virtual_interfaces.append(interface)
return virtual_interfaces
def display_interface_details(show_all=False):
"""
Display details of network interfaces, including their IP address, subnet mask,
and MAC address, in a formatted table.
Args:
show_all (bool): If True, includes both physical and virtual interfaces
in the output. Defaults to False, which only displays
physical interfaces.
Output:
Prints a table with the following columns:
- Interface: The name of the network interface.
- IP Address: The IP address assigned to the interface.
- Subnet: The subnet mask associated with the IP address.
- MAC Address: The MAC address of the interface.
Notes:
- The function uses the `ip` command to fetch interface details.
- If an interface does not have an IP address, "No IP" is displayed in the
IP Address column.
- If an error occurs while fetching details for an interface, an error
message is printed for that interface.
"""
interfaces = get_physical_interfaces()
if show_all:
interfaces.extend(get_virtual_interfaces())
interfaces.sort()
# Define column widths based on expected maximum content length
col_widths = {
'interface': 15, # Increased to accommodate longer interface names
'ip': 18, # Increased for longer IP addresses
'subnet': 10,
'mac': 18
}
# Print header with proper formatting
print(f"{'Interface':<{col_widths['interface']}} {'IP Address':<{col_widths['ip']}} {'Subnet':<{col_widths['subnet']}} {'MAC Address':<{col_widths['mac']}}")
print("-" * (col_widths['interface'] + col_widths['ip'] + col_widths['subnet'] + col_widths['mac']))
for interface in interfaces:
try:
result = subprocess.run(['ip', '-br', 'addr', 'show', interface],
capture_output=True, text=True, check=True)
if result.returncode == 0:
parts = result.stdout.strip().split()
if len(parts) >= 3:
name = parts[0]
mac = parts[1]
ip_with_mask = parts[2]
# Split IP/mask
if '/' in ip_with_mask:
ip = ip_with_mask.split('/')[0]
subnet = ip_with_mask.split('/')[1]
else:
ip = ip_with_mask
subnet = ""
print(f"{name:<{col_widths['interface']}} {ip:<{col_widths['ip']}} {subnet:<{col_widths['subnet']}} {mac:<{col_widths['mac']}}")
else:
print(f"{interface:<{col_widths['interface']}} {'No IP':<{col_widths['ip']}} {'':<{col_widths['subnet']}} {parts[1] if len(parts) > 1 else 'N/A':<{col_widths['mac']}}")
except Exception as e:
print(f"Error fetching details for {interface}: {e}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Display network interface information')
parser.add_argument('-a', '--all', action='store_true', help='Show all interfaces including virtual ones like Tailscale and WireGuard')
args = parser.parse_args()
display_interface_details(args.all)