Các dải địa chỉ IPv4 private và trường hợp biên
Hướng dẫn chính xác về RFC 1918, CGNAT, loopback, link-local, 0.0.0.0/8, multicast và các vùng IPv4 reserved kèm bài test biên bằng Python.
Tác giảYiyao
IPv4 thường được gọi chung là “địa chỉ private”, nhưng từng vùng địa chỉ có mục đích và phạm vi nhìn thấy khác nhau. Không gian private theo RFC 1918 chỉ gồm 10.0.0.0/8, 172.16.0.0/12 và 192.168.0.0/16. Loopback, link-local, CGNAT và multicast là các vùng đặc biệt khác nhau.
Bài này nêu chính xác các biên, kiểm tra địa chỉ ngay bên ngoài biên và chạy bằng module ipaddress của Python. Câu hỏi cần trả lời không chỉ là “IP này có private không?” mà còn là “nó dùng ở đâu và ai có thể nhìn thấy nó?”
Ba vùng RFC 1918
10.0.0.0/8 bao phủ 10.0.0.0 đến 10.255.255.255. 172.16.0.0/12 bao phủ 172.16.0.0 đến 172.31.255.255, tức 16 mạng /16 từ 172.16 đến 172.31. 192.168.0.0/16 bao phủ 192.168.0.0 đến 192.168.255.255.
Biên rất quan trọng: 172.15.255.255 nằm ngoài RFC 1918, 172.16.0.0 nằm trong, 172.31.255.255 nằm trong và 172.32.0.0 nằm ngoài. Không phải IP nào bắt đầu bằng 172 cũng là private.
CGNAT: không gian dùng chung, không phải RFC 1918
100.64.0.0/10, từ 100.64.0.0 đến 100.127.255.255, dành cho carrier-grade NAT. Đây là không gian dùng chung giữa khách hàng và hạ tầng NAT của nhà mạng, không thuộc ba vùng RFC 1918 nên cần được gắn nhãn riêng.
Các biên là: 100.63.255.255 nằm ngoài, 100.64.0.0 nằm trong, 100.127.255.255 nằm trong và 100.128.0.0 nằm ngoài. Không nên rút gọn CGNAT thành “mạng private thông thường”.
Loopback, link-local và 0.0.0.0/8
127.0.0.0/8 là vùng loopback. 127.0.0.1 quen thuộc nhất nhưng toàn bộ 127/8 đều dùng để máy tự truy cập chính nó. 169.254.0.0/16 là IPv4 link-local, thường được tự cấu hình khi máy không nhận được địa chỉ thông thường. Nó chỉ có hiệu lực trên local link.
0.0.0.0/8 là không gian đặc biệt “this network”. 0.0.0.0 cũng biểu thị địa chỉ chưa xác định, ví dụ server bind trên mọi interface cục bộ hoặc default route. Nó không xác định một host từ xa có thể định tuyến.
Multicast và vùng reserved
224.0.0.0/4, từ 224.0.0.0 đến 239.255.255.255, dành cho multicast. Địa chỉ này đại diện cho một nhóm nhận chứ không phải một host unicast thông thường. 240.0.0.0/4 là vùng reserved hoặc special-purpose. Cả hai không nên gọi là mạng private RFC 1918.
from ipaddress import ip_address, ip_network
CASES = [
"10.0.0.1",
"172.16.0.1", "172.31.255.254", "172.32.0.1",
"192.168.1.10",
"100.64.0.1", "100.127.255.254", "100.128.0.1",
"127.0.0.1", "169.254.10.20",
"0.0.0.0", "224.0.0.1", "8.8.8.8",
]
SPECIAL = {
"rfc1918_10": ip_network("10.0.0.0/8"),
"rfc1918_172": ip_network("172.16.0.0/12"),
"rfc1918_192": ip_network("192.168.0.0/16"),
"cgnat": ip_network("100.64.0.0/10"),
"loopback": ip_network("127.0.0.0/8"),
"link_local": ip_network("169.254.0.0/16"),
"this_network": ip_network("0.0.0.0/8"),
"multicast": ip_network("224.0.0.0/4"),
}
def classify(value: str) -> dict:
ip = ip_address(value)
labels = [name for name, network in SPECIAL.items() if ip in network]
return {
"input": value,
"normalized": str(ip),
"is_private": ip.is_private,
"is_global": ip.is_global,
"is_loopback": ip.is_loopback,
"is_link_local": ip.is_link_local,
"is_unspecified": ip.is_unspecified,
"is_multicast": ip.is_multicast,
"special_ranges": labels,
}
for value in CASES:
print(classify(value))
Kết quả tiêu biểu: 10.0.0.1 có is_private=True và is_global=False; 172.15.255.255 không private; 100.64.0.1 không phải private RFC 1918 và cũng không global; 127.0.0.1 có is_loopback=True; 169.254.10.20 có is_link_local=True; 224.0.0.1 có is_multicast=True. Khi business rule cần phân biệt, hãy giữ nhãn vùng rõ ràng.
Kiểm tra biên có thể chạy ngay
from ipaddress import ip_address, ip_network
PRIVATE = (
ip_network("10.0.0.0/8"),
ip_network("172.16.0.0/12"),
ip_network("192.168.0.0/16"),
)
CGNAT = ip_network("100.64.0.0/10")
def routing_bucket(value: str) -> str:
ip = ip_address(value)
if any(ip in network for network in PRIVATE):
return "RFC1918 private address"
if ip in CGNAT:
return "shared address space / CGNAT (100.64/10)"
if ip.is_loopback:
return "loopback (local host only)"
if ip.is_link_local:
return "link-local (local segment)"
if ip.is_unspecified:
return "unspecified / this network"
if ip.is_multicast:
return "multicast"
if ip.is_global:
return "globally routable candidate"
return "special-purpose or non-global address"
for sample in ["172.15.255.255", "172.16.0.0", "172.31.255.255",
"172.32.0.0", "100.63.255.255", "100.64.0.0",
"100.127.255.255", "100.128.0.0"]:
print(sample, "=>", routing_bucket(sample))
Output biên dự kiến: 172.15.255.255 => globally routable candidate; 172.16.0.0 => RFC1918 private address; 172.31.255.255 => RFC1918 private address; 172.32.0.0 => globally routable candidate; 100.63.255.255 => globally routable candidate; 100.64.0.0 => shared address space / CGNAT; 100.127.255.255 => shared address space / CGNAT; 100.128.0.0 => globally routable candidate.
Private, local, internal và publicly visible khác nhau
“Private” thường chỉ địa chỉ RFC 1918, được tái sử dụng trong các mạng khác nhau và không được quảng bá như đích Internet công cộng thông thường. “Local” nói về phạm vi, ví dụ loopback chỉ tới máy hiện tại còn link-local chỉ tới local link. “Internal” là mô tả vận hành, có thể bao gồm RFC 1918, CGNAT, VPN hoặc vùng riêng của tổ chức.
“Publicly visible” mô tả địa chỉ mà một phía quan sát được. Browser hoặc server từ xa thường thấy địa chỉ public sau NAT, còn ứng dụng trong LAN thấy địa chỉ local. Địa chỉ CGNAT có thể là không gian nội bộ của nhà mạng nhưng người dùng không kiểm soát và thường không nhận kết nối inbound trực tiếp từ Internet. Chỉ phân loại IPv4 không cho biết website từ xa sẽ thấy địa chỉ nào.
Cách áp dụng thực tế
Với firewall, hãy so sánh CIDR cụ thể và ghi rõ mục đích. Với log, giữ địa chỉ gốc cùng lý do phân loại. Với chẩn đoán proxy hoặc mạng, ghi cả địa chỉ interface cục bộ và địa chỉ egress mà bên ngoài quan sát được. Đừng biến mọi địa chỉ non-global thành “private”, vì như vậy sẽ mất sự khác biệt giữa RFC 1918, CGNAT, loopback, link-local và multicast.
Kết luận
Quy trình đáng tin cậy là parse địa chỉ, so sánh với các vùng special-purpose rõ ràng, kiểm tra các giá trị sát biên và giải thích visibility theo ngữ cảnh mạng. RFC 1918 là ba vùng chính xác; 100.64/10, loopback, link-local, 0/8 và multicast cần nhãn riêng.
