跳到主要内容

网络地址类型

PostgreSQL 提供 inet、cidr、macaddr 和 macaddr8 保存网络地址。它们会验证格式并提供比字符串更可靠的比较、包含和掩码运算。

inet 与 cidr​

inet 表示主机地址或带掩码的网络地址,例如 192.0.2.10/24;cidr 表示网络块,主机位应为零,例如 192.0.2.0/24:

SELECT '192.0.2.10/24'::inet;
SELECT '192.0.2.0/24'::cidr;

IPv4 和 IPv6 都支持。inet 更适合请求来源 IP、服务器地址;cidr 更适合网段、白名单和路由前缀。

网络运算​

SELECT inet '192.0.2.10' << inet '192.0.2.0/24' AS inside;
SELECT cidr '192.0.2.0/24' >>= cidr '192.0.2.0/25' AS contains;
SELECT inet '192.0.2.10' - inet '192.0.2.1' AS address_distance;

<<、>> 等运算符用于严格包含或包含关系,具体语义应根据操作数类型查阅 PostgreSQL 文档。masklen、host、network 等函数可拆分地址和掩码:

SELECT host(ip_address), masklen(ip_address), network(ip_address)
FROM access_logs;

表设计示例​

CREATE TABLE access_logs (
request_id bigint PRIMARY KEY,
client_ip inet NOT NULL,
allowed_network cidr,
CHECK (family(client_ip) IN (4, 6))
);

CREATE INDEX access_logs_client_ip_idx ON access_logs (client_ip);

inet 的 B-tree 索引适合排序和等值查询;GiST/SP-GiST 索引可用于部分包含关系。大型网络白名单应评估索引类型和查询计划,不要仅凭运算符名称猜测性能。

IPv4、IPv6 和标准化​

应用层应接受并标准化 IPv4、IPv6 文本,特别是 IPv4-mapped IPv6 地址。不要用字符串比较判断两个地址是否相同,inet 会按地址语义处理表示形式。

记录来源 IP 时还应考虑反向代理:客户端传来的 X-Forwarded-For 只有在代理链可信且配置正确时才能使用。数据库类型能校验地址格式,但不能证明地址真实来源。

MAC 地址​

macaddr 保存 6 字节 MAC 地址,macaddr8 保存 EUI-64 地址:

SELECT '08:00:2b:01:02:03'::macaddr;

MAC 地址可能被随机化,不能自动当作稳定用户标识;合规和隐私设计应单独评估。

常见误区​

  • 用 varchar(45) 保存 IP,失去格式校验和网络运算能力。
  • 把 inet 和 cidr 混用,导致主机位、掩码和包含语义不清。
  • 用字符串排序推断 IP 大小。
  • 未验证代理链就信任转发头中的客户端地址。
  • 把 MAC 地址当永久设备身份或用户身份。