Last active
April 12, 2024 13:46
-
-
Save Grynn/cb47f73618df001b6b3f5ada99cd2ccb to your computer and use it in GitHub Desktop.
Show all IP addresses with scope in a nice table format
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import sys | |
import os | |
import json | |
import pandas as pd | |
import ipaddress | |
private_ranges = [ | |
ipaddress.IPv4Network("10.0.0.0/8"), | |
ipaddress.IPv4Network("172.16.0.0/12"), | |
ipaddress.IPv4Network("192.168.0.0/16"), | |
ipaddress.IPv4Network("127.0.0.0/8"), | |
ipaddress.IPv6Network("::1/128"), | |
ipaddress.IPv6Network("fc00::/7"), | |
] | |
special_ranges = [ | |
ipaddress.IPv4Network("100.64.0.0/10") | |
] | |
scope_priority = { | |
"global": 1, | |
"tailscale": 2, | |
"bogon": 3, | |
"local": 4 | |
} | |
def is_special(ip_str): | |
try: | |
ip_obj = ipaddress.ip_address(ip_str) | |
except ValueError: | |
print(f"Invalid IP address: {ip_str}") | |
return None | |
for network in special_ranges: | |
if ip_obj in network: | |
return True | |
return False | |
def is_bogon(ip_str): | |
""" | |
Determines if an IP address is local (non-routable, aka bogon) or global. | |
Args: | |
ip_str (str): The IP address to check. | |
Returns: | |
bool: True if the IP address is local, False if it's global. | |
""" | |
try: | |
ip_obj = ipaddress.ip_address(ip_str) | |
except ValueError: | |
print(f"Invalid IP address: {ip_str}") | |
return None | |
for network in private_ranges: | |
if ip_obj in network: | |
return True | |
return False | |
def main(): | |
# run ip --json address list and parse the output | |
cmd = "ip --json address list" | |
result = os.popen(cmd).read() | |
# parse result as JSON | |
data = json.loads(result) | |
# make a dataframe with the following columns: interface, ip, prefixlen, scope | |
rows = [] | |
for interface in data: | |
for addr in interface['addr_info']: | |
scope = addr["scope"] | |
ip_addr_str = addr["local"] | |
prefixlen = addr["prefixlen"] | |
if scope == "global": | |
if is_bogon(ip_addr_str): scope = "bogon" | |
if is_special(ip_addr_str): scope = "tailscale" | |
rows.append({ | |
"interface": interface['ifname'], | |
"ip": f"{ip_addr_str}/{prefixlen}", | |
"scope": scope}) | |
df = pd.DataFrame(rows, columns=["interface", "ip", "scope"]) | |
# print the dataframe sorted by scope (global, then bogon, then local) | |
print(df.sort_values(by="scope", key=lambda x: x.map(scope_priority))) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment