ipv6-first
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseIPv6-First Development
IPv6优先开发
Overview
概述
IPv6 is the present and future of networking. IPv4 is legacy.
This skill enforces IPv6-first development across all code, tests, documentation, and infrastructure.
Core principle: Design for IPv6. Add IPv4 only when legacy compatibility is explicitly required.
Announce at start: "I'm following ipv6-first principles - IPv6 is the primary protocol, IPv4 only for legacy support."
IPv6是网络的现在与未来。IPv4属于遗留技术。
本技能要求在所有代码、测试、文档和基础设施中遵循IPv6优先的开发原则。
核心原则: 针对IPv6进行设计。仅在明确需要遗留兼容性时才添加IPv4支持。
启动时声明: "我遵循IPv6优先原则——IPv6是主要协议,IPv4仅用于遗留支持。"
The Rule
规则
| Protocol | Status | Priority |
|---|---|---|
| IPv6 | First-class citizen | Primary, default, required |
| IPv4 | Legacy support | Secondary, optional, deprecated path |
| 协议 | 状态 | 优先级 |
|---|---|---|
| IPv6 | 一等公民 | 主要、默认、强制要求 |
| IPv4 | 遗留支持 | 次要、可选、已弃用路径 |
What This Means
具体要求
Code
代码
python
undefinedpython
undefinedCORRECT: IPv6 first
CORRECT: IPv6 first
def connect(host: str, port: int) -> Connection:
# Try IPv6 first
for family in [socket.AF_INET6, socket.AF_INET]:
try:
return _connect(host, port, family)
except OSError:
continue
raise ConnectionError(f"Cannot connect to {host}:{port}")
def connect(host: str, port: int) -> Connection:
# Try IPv6 first
for family in [socket.AF_INET6, socket.AF_INET]:
try:
return _connect(host, port, family)
except OSError:
continue
raise ConnectionError(f"Cannot connect to {host}:{port}")
WRONG: IPv4 assumed
WRONG: IPv4 assumed
def connect(host: str, port: int) -> Connection:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # IPv4 only!
sock.connect((host, port))
undefineddef connect(host: str, port: int) -> Connection:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # IPv4 only!
sock.connect((host, port))
undefinedSocket Binding
Socket绑定
python
undefinedpython
undefinedCORRECT: Dual-stack with IPv6 primary
CORRECT: Dual-stack with IPv6 primary
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) # Accept IPv4 via mapped addresses
sock.bind(('::', port))
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) # Accept IPv4 via mapped addresses
sock.bind(('::', port))
WRONG: IPv4 only
WRONG: IPv4 only
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('0.0.0.0', port))
undefinedsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('0.0.0.0', port))
undefinedConfiguration Files
配置文件
yaml
undefinedyaml
undefinedCORRECT: IPv6 addresses shown first, with examples
CORRECT: IPv6 addresses shown first, with examples
server:
Primary: IPv6 (recommended)
bind: "::1"
Legacy: IPv4 (for compatibility only)
bind: "127.0.0.1"
Examples:
IPv6: "2001:db8::1", "::1", "::"
IPv4 (legacy): "192.168.1.1", "127.0.0.1", "0.0.0.0"
server:
Primary: IPv6 (recommended)
bind: "::1"
Legacy: IPv4 (for compatibility only)
bind: "127.0.0.1"
Examples:
IPv6: "2001:db8::1", "::1", "::"
IPv4 (legacy): "192.168.1.1", "127.0.0.1", "0.0.0.0"
WRONG: IPv4 as default with no IPv6 mention
WRONG: IPv4 as default with no IPv6 mention
server:
bind: "127.0.0.1"
undefinedserver:
bind: "127.0.0.1"
undefinedDocumentation
文档
markdown
undefinedmarkdown
undefinedCORRECT: IPv6 first in docs
CORRECT: IPv6 first in docs
Connecting to the Server
Connecting to the Server
Connect using the server's IPv6 address:
ssh user@2001:db8:85a3::8a2e:370:7334For legacy IPv4 networks:
ssh user@192.0.2.1Connect using the server's IPv6 address:
ssh user@2001:db8:85a3::8a2e:370:7334For legacy IPv4 networks:
ssh user@192.0.2.1WRONG: IPv4 assumed
WRONG: IPv4 assumed
Connecting to the Server
Connecting to the Server
ssh user@192.0.2.1
undefinedssh user@192.0.2.1
undefinedTests
测试
python
undefinedpython
undefinedCORRECT: Test IPv6 primarily, IPv4 as legacy path
CORRECT: Test IPv6 primarily, IPv4 as legacy path
class TestNetworkConnection:
def test_ipv6_connection(self):
"""Primary test: IPv6 connectivity."""
conn = connect("::1", 8080)
assert conn.family == socket.AF_INET6
def test_ipv4_legacy_connection(self):
"""Legacy support: IPv4 connectivity for older networks."""
conn = connect("127.0.0.1", 8080)
assert conn.family == socket.AF_INET
def test_dual_stack_prefers_ipv6(self):
"""When both available, IPv6 should be preferred."""
conn = connect("localhost", 8080)
assert conn.family == socket.AF_INET6class TestNetworkConnection:
def test_ipv6_connection(self):
"""Primary test: IPv6 connectivity."""
conn = connect("::1", 8080)
assert conn.family == socket.AF_INET6
def test_ipv4_legacy_connection(self):
"""Legacy support: IPv4 connectivity for older networks."""
conn = connect("127.0.0.1", 8080)
assert conn.family == socket.AF_INET
def test_dual_stack_prefers_ipv6(self):
"""When both available, IPv6 should be preferred."""
conn = connect("localhost", 8080)
assert conn.family == socket.AF_INET6WRONG: Only testing IPv4
WRONG: Only testing IPv4
class TestNetworkConnection:
def test_connection(self):
conn = connect("127.0.0.1", 8080)
assert conn.is_connected()
undefinedclass TestNetworkConnection:
def test_connection(self):
conn = connect("127.0.0.1", 8080)
assert conn.is_connected()
undefinedDNS and Hostname Resolution
DNS与主机名解析
python
undefinedpython
undefinedCORRECT: Request AAAA records first
CORRECT: Request AAAA records first
def resolve_host(hostname: str) -> list[str]:
addresses = []
# IPv6 first (AAAA records)
try:
for info in socket.getaddrinfo(hostname, None, socket.AF_INET6):
addresses.append(info[4][0])
except socket.gaierror:
pass
# IPv4 fallback (A records) for legacy
try:
for info in socket.getaddrinfo(hostname, None, socket.AF_INET):
addresses.append(info[4][0])
except socket.gaierror:
pass
return addressesdef resolve_host(hostname: str) -> list[str]:
addresses = []
# IPv6 first (AAAA records)
try:
for info in socket.getaddrinfo(hostname, None, socket.AF_INET6):
addresses.append(info[4][0])
except socket.gaierror:
pass
# IPv4 fallback (A records) for legacy
try:
for info in socket.getaddrinfo(hostname, None, socket.AF_INET):
addresses.append(info[4][0])
except socket.gaierror:
pass
return addressesWRONG: Only resolving A records
WRONG: Only resolving A records
def resolve_host(hostname: str) -> str:
return socket.gethostbyname(hostname) # IPv4 only!
undefineddef resolve_host(hostname: str) -> str:
return socket.gethostbyname(hostname) # IPv4 only!
undefinedEnvironment Variables and Defaults
环境变量与默认值
bash
undefinedbash
undefinedCORRECT: IPv6 defaults
CORRECT: IPv6 defaults
export SERVER_HOST="${SERVER_HOST:-::1}"
export BIND_ADDRESS="${BIND_ADDRESS:-::}"
export SERVER_HOST="${SERVER_HOST:-::1}"
export BIND_ADDRESS="${BIND_ADDRESS:-::}"
WRONG: IPv4 defaults
WRONG: IPv4 defaults
export SERVER_HOST="${SERVER_HOST:-127.0.0.1}"
export BIND_ADDRESS="${BIND_ADDRESS:-0.0.0.0}"
undefinedexport SERVER_HOST="${SERVER_HOST:-127.0.0.1}"
export BIND_ADDRESS="${BIND_ADDRESS:-0.0.0.0}"
undefinedDatabase Connection Strings
数据库连接字符串
python
undefinedpython
undefinedCORRECT: IPv6 address format (brackets required for port separation)
CORRECT: IPv6 address format (brackets required for port separation)
DATABASE_URL = "postgresql://user:pass@[2001:db8::1]:5432/mydb"
DATABASE_URL = "postgresql://user:pass@[2001:db8::1]:5432/mydb"
Also correct: IPv6 localhost
Also correct: IPv6 localhost
DATABASE_URL = "postgresql://user:pass@[::1]:5432/mydb"
DATABASE_URL = "postgresql://user:pass@[::1]:5432/mydb"
Legacy IPv4
Legacy IPv4
DATABASE_URL = "postgresql://user:pass@192.168.1.100:5432/mydb"
undefinedDATABASE_URL = "postgresql://user:pass@192.168.1.100:5432/mydb"
undefinedURL Construction
URL构建
python
undefinedpython
undefinedCORRECT: Handle IPv6 addresses in URLs (require brackets)
CORRECT: Handle IPv6 addresses in URLs (require brackets)
def build_url(host: str, port: int, path: str = "") -> str:
if ":" in host: # IPv6 address
return f"http://[{host}]:{port}{path}"
return f"http://{host}:{port}{path}"
def build_url(host: str, port: int, path: str = "") -> str:
if ":" in host: # IPv6 address
return f"http://[{host}]:{port}{path}"
return f"http://{host}:{port}{path}"
Usage:
Usage:
build_url("2001:db8::1", 8080, "/api") -> "http://[2001:db8::1]:8080/api"
build_url("2001:db8::1", 8080, "/api") -> "http://[2001:db8::1]:8080/api"
build_url("192.168.1.1", 8080, "/api") -> "http://192.168.1.1:8080/api"
build_url("192.168.1.1", 8080, "/api") -> "http://192.168.1.1:8080/api"
undefinedundefinedValidation Patterns
验证模式
IP Address Validation
IP地址验证
python
import ipaddress
def validate_ip(addr: str) -> tuple[str, str]:
"""
Validate IP address and return (normalized_address, version).
IPv6 is preferred.
"""
try:
ip = ipaddress.ip_address(addr)
version = "ipv6" if ip.version == 6 else "ipv4-legacy"
return (str(ip), version)
except ValueError as e:
raise ValueError(f"Invalid IP address: {addr}") from e
def is_ipv6(addr: str) -> bool:
"""Check if address is IPv6 (the preferred protocol)."""
try:
return ipaddress.ip_address(addr).version == 6
except ValueError:
return Falsepython
import ipaddress
def validate_ip(addr: str) -> tuple[str, str]:
"""
Validate IP address and return (normalized_address, version).
IPv6 is preferred.
"""
try:
ip = ipaddress.ip_address(addr)
version = "ipv6" if ip.version == 6 else "ipv4-legacy"
return (str(ip), version)
except ValueError as e:
raise ValueError(f"Invalid IP address: {addr}") from e
def is_ipv6(addr: str) -> bool:
"""Check if address is IPv6 (the preferred protocol)."""
try:
return ipaddress.ip_address(addr).version == 6
except ValueError:
return FalseNetwork Range Validation
网络范围验证
python
undefinedpython
undefinedCORRECT: Support both, prefer IPv6
CORRECT: Support both, prefer IPv6
ALLOWED_NETWORKS = [
# IPv6 networks (primary)
ipaddress.ip_network("2001:db8::/32"),
ipaddress.ip_network("fd00::/8"), # ULA
# IPv4 networks (legacy support)
ipaddress.ip_network("10.0.0.0/8"),
ipaddress.ip_network("192.168.0.0/16"),]
undefinedALLOWED_NETWORKS = [
# IPv6 networks (primary)
ipaddress.ip_network("2001:db8::/32"),
ipaddress.ip_network("fd00::/8"), # ULA
# IPv4 networks (legacy support)
ipaddress.ip_network("10.0.0.0/8"),
ipaddress.ip_network("192.168.0.0/16"),]
undefinedComments and Naming
注释与命名
When IPv4 is included for legacy support, comment it as such:
python
undefined当为遗留支持添加IPv4时,需将其标记为遗留:
python
undefinedBind to all interfaces
Bind to all interfaces
IPv6 (primary) - handles both IPv6 and IPv4-mapped addresses
IPv6 (primary) - handles both IPv6 and IPv4-mapped addresses
server.bind("::", port)
server.bind("::", port)
Legacy IPv4-only fallback (deprecated path)
Legacy IPv4-only fallback (deprecated path)
if not ipv6_available:
server.bind("0.0.0.0", port)
```pythonif not ipv6_available:
server.bind("0.0.0.0", port)
```pythonVariable naming should reflect the hierarchy
Variable naming should reflect the hierarchy
primary_address: str # IPv6
legacy_address: str # IPv4 (only when needed)
primary_address: str # IPv6
legacy_address: str # IPv4 (only when needed)
NOT:
NOT:
ipv4_address: str
ipv6_address: str # This implies equal status
undefinedipv4_address: str
ipv6_address: str # This implies equal status
undefinedError Messages
错误消息
python
undefinedpython
undefinedCORRECT: IPv6-first messaging
CORRECT: IPv6-first messaging
raise ConnectionError(
f"Cannot connect to {host}. "
f"Ensure the server is accessible via IPv6 (preferred) or IPv4 (legacy)."
)
raise ConnectionError(
f"Cannot connect to {host}. "
f"Ensure the server is accessible via IPv6 (preferred) or IPv4 (legacy)."
)
WRONG: IPv4 assumed
WRONG: IPv4 assumed
raise ConnectionError(
f"Cannot connect to {host}. Check your network connection."
)
undefinedraise ConnectionError(
f"Cannot connect to {host}. Check your network connection."
)
undefinedWhen IPv4 is Required
何时需要IPv4
Add IPv4 support only when:
- Interfacing with legacy systems that don't support IPv6
- Required by external API or service constraints
- Explicitly requested for backward compatibility
- Cloud provider or infrastructure limitation (document this!)
Always document why IPv4 is needed:
python
undefined仅在以下情况添加IPv4支持:
- 与不支持IPv6的遗留系统交互时
- 受外部API或服务限制时
- 明确要求向后兼容时
- 云提供商或基础设施存在限制时(请记录此情况!)
务必记录需要IPv4的原因:
python
undefinedIPv4 required: AWS Classic Load Balancer doesn't support IPv6
IPv4 required: AWS Classic Load Balancer doesn't support IPv6
TODO: Migrate to ALB when possible for IPv6 support
TODO: Migrate to ALB when possible for IPv6 support
legacy_endpoint = "http://192.0.2.1:8080/api"
undefinedlegacy_endpoint = "http://192.0.2.1:8080/api"
undefinedChecklist
检查清单
When writing network code:
- Default addresses use IPv6 (/
::not::1/0.0.0.0)127.0.0.1 - Socket creation uses by default
AF_INET6 - Dual-stack is enabled where appropriate
- Tests cover IPv6 primarily, IPv4 as legacy path
- Documentation shows IPv6 examples first
- Configuration examples use IPv6 addresses
- URL handling accounts for IPv6 bracket notation
- IPv4 code paths are commented as "legacy"
- Any IPv4-only code has documented justification
编写网络代码时:
- 默认地址使用IPv6(/
::而非::1/0.0.0.0)127.0.0.1 - Socket创建默认使用
AF_INET6 - 在适当情况下启用双栈
- 测试以IPv6为主,IPv4作为遗留路径
- 文档优先展示IPv6示例
- 配置示例使用IPv6地址
- URL处理支持IPv6的括号表示法
- IPv4代码路径标记为"遗留"
- 任何仅支持IPv4的代码都有文档说明理由