ipv6-first

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

IPv6-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

规则

ProtocolStatusPriority
IPv6First-class citizenPrimary, default, required
IPv4Legacy supportSecondary, optional, deprecated path
协议状态优先级
IPv6一等公民主要、默认、强制要求
IPv4遗留支持次要、可选、已弃用路径

What This Means

具体要求

Code

代码

python
undefined
python
undefined

CORRECT: 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))
undefined
def connect(host: str, port: int) -> Connection: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # IPv4 only! sock.connect((host, port))
undefined

Socket Binding

Socket绑定

python
undefined
python
undefined

CORRECT: 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))
undefined
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('0.0.0.0', port))
undefined

Configuration Files

配置文件

yaml
undefined
yaml
undefined

CORRECT: 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"
undefined
server: bind: "127.0.0.1"
undefined

Documentation

文档

markdown
undefined
markdown
undefined

CORRECT: 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:7334
For legacy IPv4 networks:
ssh user@192.0.2.1

Connect using the server's IPv6 address:
ssh user@2001:db8:85a3::8a2e:370:7334
For legacy IPv4 networks:
ssh user@192.0.2.1

WRONG: IPv4 assumed

WRONG: IPv4 assumed

Connecting to the Server

Connecting to the Server

ssh user@192.0.2.1
undefined
ssh user@192.0.2.1
undefined

Tests

测试

python
undefined
python
undefined

CORRECT: 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_INET6
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_INET6

WRONG: Only testing IPv4

WRONG: Only testing IPv4

class TestNetworkConnection: def test_connection(self): conn = connect("127.0.0.1", 8080) assert conn.is_connected()
undefined
class TestNetworkConnection: def test_connection(self): conn = connect("127.0.0.1", 8080) assert conn.is_connected()
undefined

DNS and Hostname Resolution

DNS与主机名解析

python
undefined
python
undefined

CORRECT: 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 addresses
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 addresses

WRONG: Only resolving A records

WRONG: Only resolving A records

def resolve_host(hostname: str) -> str: return socket.gethostbyname(hostname) # IPv4 only!
undefined
def resolve_host(hostname: str) -> str: return socket.gethostbyname(hostname) # IPv4 only!
undefined

Environment Variables and Defaults

环境变量与默认值

bash
undefined
bash
undefined

CORRECT: 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}"
undefined
export SERVER_HOST="${SERVER_HOST:-127.0.0.1}" export BIND_ADDRESS="${BIND_ADDRESS:-0.0.0.0}"
undefined

Database Connection Strings

数据库连接字符串

python
undefined
python
undefined

CORRECT: 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"
undefined
DATABASE_URL = "postgresql://user:pass@192.168.1.100:5432/mydb"
undefined

URL Construction

URL构建

python
undefined
python
undefined

CORRECT: 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"

undefined
undefined

Validation 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 False
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 False

Network Range Validation

网络范围验证

python
undefined
python
undefined

CORRECT: 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"),
]
undefined
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"),
]
undefined

Comments and Naming

注释与命名

When IPv4 is included for legacy support, comment it as such:
python
undefined
当为遗留支持添加IPv4时,需将其标记为遗留:
python
undefined

Bind 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)

```python
if not ipv6_available: server.bind("0.0.0.0", port)

```python

Variable 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
undefined
ipv4_address: str ipv6_address: str # This implies equal status
undefined

Error Messages

错误消息

python
undefined
python
undefined

CORRECT: 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." )
undefined
raise ConnectionError( f"Cannot connect to {host}. Check your network connection." )
undefined

When IPv4 is Required

何时需要IPv4

Add IPv4 support only when:
  1. Interfacing with legacy systems that don't support IPv6
  2. Required by external API or service constraints
  3. Explicitly requested for backward compatibility
  4. Cloud provider or infrastructure limitation (document this!)
Always document why IPv4 is needed:
python
undefined
仅在以下情况添加IPv4支持:
  1. 与不支持IPv6的遗留系统交互时
  2. 受外部API或服务限制时
  3. 明确要求向后兼容时
  4. 云提供商或基础设施存在限制时(请记录此情况!)
务必记录需要IPv4的原因:
python
undefined

IPv4 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"
undefined
legacy_endpoint = "http://192.0.2.1:8080/api"
undefined

Checklist

检查清单

When writing network code:
  • Default addresses use IPv6 (
    ::
    /
    ::1
    not
    0.0.0.0
    /
    127.0.0.1
    )
  • Socket creation uses
    AF_INET6
    by default
  • 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的代码都有文档说明理由