Coverage for src / local_deep_research / security / network_utils.py: 100%
11 statements
« prev ^ index » next coverage.py v7.12.0, created at 2026-01-11 00:51 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2026-01-11 00:51 +0000
1"""Network utility functions for IP address classification.
3This module provides utilities for classifying IP addresses and hostnames
4as private/local vs public. Used for URL normalization and security validation.
5"""
7import ipaddress
10def is_private_ip(hostname: str) -> bool:
11 """Check if hostname is a private/local IP address.
13 Recognizes:
14 - Localhost values (127.0.0.1, localhost, [::1], 0.0.0.0)
15 - RFC 1918 private IPv4 ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
16 - IPv6 private addresses (fc00::/7, fe80::/10)
17 - mDNS .local domains
19 Args:
20 hostname: The hostname or IP address to check
22 Returns:
23 True if the hostname is a private/local address, False otherwise
25 Examples:
26 >>> is_private_ip("192.168.1.100")
27 True
28 >>> is_private_ip("172.16.0.50")
29 True
30 >>> is_private_ip("10.0.0.1")
31 True
32 >>> is_private_ip("8.8.8.8")
33 False
34 >>> is_private_ip("api.openai.com")
35 False
36 """
37 # Known localhost values
38 if hostname in ("localhost", "127.0.0.1", "[::1]", "0.0.0.0"):
39 return True
41 # Handle bracketed IPv6
42 if hostname.startswith("[") and hostname.endswith("]"):
43 hostname = hostname[1:-1]
45 try:
46 ip = ipaddress.ip_address(hostname)
47 # Check if private (includes 10.x, 172.16-31.x, 192.168.x, fc00::/7, etc.)
48 # Also check loopback and link-local
49 return ip.is_private or ip.is_loopback or ip.is_link_local
50 except ValueError:
51 # Not a valid IP address, check for .local domain (mDNS)
52 return hostname.endswith(".local")