64 lines
1.6 KiB
Python
64 lines
1.6 KiB
Python
#!/usr/bin/env python3
|
|
"""IP helper functions for the intrusion-detection system."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import ipaddress
|
|
from typing import Iterable
|
|
|
|
from whitelists import WHITELIST_NETS as _WHITELIST_NETS
|
|
|
|
|
|
def parse_ip(value: str):
|
|
"""Return an ip_address object, or None if `value` is not an IP."""
|
|
try:
|
|
return ipaddress.ip_address(value)
|
|
except (ValueError, TypeError):
|
|
return None
|
|
|
|
|
|
def ip_version(value: str) -> int | None:
|
|
addr = parse_ip(value)
|
|
return addr.version if addr else None
|
|
|
|
|
|
def is_ipv6(value: str) -> bool:
|
|
return ip_version(value) == 6
|
|
|
|
|
|
def is_ipv4(value: str) -> bool:
|
|
return ip_version(value) == 4
|
|
|
|
|
|
def whitelist_of(value: str) -> str | None:
|
|
"""Return the whitelist name an IP belongs to, else None."""
|
|
addr = parse_ip(value)
|
|
if addr is None:
|
|
return None
|
|
for name, nets in _WHITELIST_NETS.items():
|
|
for net in nets:
|
|
if addr.version == net.version and addr in net:
|
|
return name
|
|
return None
|
|
|
|
|
|
def is_whitelisted(value: str) -> bool:
|
|
return whitelist_of(value) is not None
|
|
|
|
|
|
def sort_ips(ips: Iterable[str]) -> list[str]:
|
|
"""Numeric sort, IPv4 before IPv6, unparseable last."""
|
|
def key(ip: str):
|
|
addr = parse_ip(ip)
|
|
if addr is None:
|
|
return (9, b"", ip)
|
|
return (addr.version, addr.packed, "")
|
|
return sorted(ips, key=key)
|
|
|
|
|
|
def split_versions(ips: Iterable[str]) -> tuple[list[str], list[str]]:
|
|
"""Split an IP iterable into (sorted IPv4, sorted IPv6)."""
|
|
ips = list(ips)
|
|
return (sort_ips(ip for ip in ips if is_ipv4(ip)),
|
|
sort_ips(ip for ip in ips if is_ipv6(ip)))
|