Go net.IPMask.Size 怎样判断掩码是否是连续前缀
来源:17golang原创
时间:2026-11-07 07:26:54 424浏览 收藏
我第一次把 IP 白名单从字符串改成 net.IPNet 时,最容易误判的就是 net.IPMask.Size() 返回的两个零。这个方法不是简单地数 1 的个数,而是在判断掩码是否符合“前面连续是 1,后面连续是 0”的规范形状。连续掩码会返回前缀长度和总位数;非连续掩码返回 (0, 0)。但合法的 IPv4 /0 返回的是 (0, 32),不能混为一谈。
ones是前导 1 的数量,bits是掩码总位数。- IPv4 常见结果是
(24, 32),IPv6 的/64是(64, 128)。 - 判断是否为连续 CIDR 前缀时,先看
bits == 0,再看ones,不要只判断ones == 0。
调用Go标准库的`mask.Size()`方法会返回两个整数,第一个是前缀位长度,第二个是掩码总有效位长度,如果返回的错误值为nil,就说明当前IPMask是连续的前缀掩码,非连续掩码会直接返回size为0和对应的错误信息。
先把 Size 的两个返回值看懂
官方定义很直接:Size 返回掩码的前导 1 数量和总位数;如果掩码不是“1 后跟 0”的规范形式,就返回 0, 0。因此它同时回答两个问题:这个掩码有多长,以及它能不能被解释成 CIDR 前缀。
这里的数字是语义基线,不是压测数据。255.255.255.0 的基线是 24/32,代表 IPv4 的 /24;IPv6 的 /64 则是 64/128。这组数字比把掩码转成字符串再手工统计更稳定,也不会把 IPv4 和 IPv6 的宽度混在一起。

用 IPv4 和 IPv6 掩码做一次对照
构造标准掩码时,net.IPv4Mask 适合表达 4 字节 IPv4 掩码,net.CIDRMask 适合按前缀长度构造 IPv4 或 IPv6 掩码。它们都能和 Size 互相对照:前缀长度是 ones,地址族宽度是 bits。
package main
import (
"fmt"
"net"
)
func main() {
ipv4Mask := net.IPv4Mask(255, 255, 255, 0)
ones4, bits4 := ipv4Mask.Size()
fmt.Printf("IPv4: %d/%d\n", ones4, bits4) // 输出前缀长度和 IPv4 总位数
ipv6Mask := net.CIDRMask(64, 128)
ones6, bits6 := ipv6Mask.Size()
fmt.Printf("IPv6: %d/%d\n", ones6, bits6) // 输出 IPv6 的 /64 语义
}
这段代码对应的结果应当是 IPv4: 24/32 和 IPv6: 64/128。如果业务只接收 IPv4,就可以把 bits 固定约束为 32;如果同时接收两种地址族,就应保留这个返回值,不要只保存 ones。
(0, 0) 到底代表什么
(0, 0) 的含义是“无法按规范的连续前缀解释”。例如 11111111 00001111 00000000 00000000 在第一个 0 后又出现了 1,它不是标准 CIDR 掩码,Size 就不会把它猜成某个前缀。
反过来,合法的全零 IPv4 掩码是 /0,结果应是 (0, 32);全零 IPv6 掩码是 (0, 128)。所以分类时应先用 bits == 0 识别非规范形状,再接受 ones == 0 但 bits > 0 的合法零前缀。

封装一个不会误判 /0 的分类函数
如果这个判断会出现在配置加载或白名单解析里,建议集中封装,避免多个调用点各自猜测 (0, 0) 的含义。函数可以同时返回前缀长度、地址族宽度和是否为连续掩码。
package netmask
import "net"
// PrefixInfo 把 Size 的两个整数转换成调用方容易判断的结果。
type PrefixInfo struct {
Ones int // 连续前缀中的 1 数量
Bits int // IPv4 为 32,IPv6 为 128
Valid bool // 是否为 1 后跟 0 的规范掩码
}
func Inspect(mask net.IPMask) PrefixInfo {
ones, bits := mask.Size()
// bits 为 0 是 Size 表示的非规范形状;ones 为 0 不一定错误,/0 仍合法。
return PrefixInfo{Ones: ones, Bits: bits, Valid: bits != 0}
}
这段封装只判断掩码形状,不判断它是否和某个 IP 属于同一个网络。后一个问题应交给 net.IPNet 的 Contains;不要把“掩码连续”误当成“地址匹配成功”。
排查时记住这张小表
| 掩码语义 | Size 结果 | 结论 |
|---|---|---|
| IPv4 /0 | 0, 32 | 合法连续前缀 |
| IPv4 /24 | 24, 32 | 合法连续前缀 |
| IPv6 /64 | 64, 128 | 合法连续前缀 |
| 1 后又出现 1 的非连续掩码 | 0, 0 | 不能按 CIDR 前缀解释 |
我的实际判断顺序是:先看 bits 是否为 0,再按 32 或 128 判断地址族,最后使用 ones 作为前缀长度。这样既保留了零前缀,也能把非规范掩码尽早挡在配置边界之外。
常见追问
Size 返回 (0, 0) 能当成 IPv4 /0 吗?
不能。IPv4 /0 的总位数仍然是 32,正确结果是 (0, 32);(0, 0) 表示无法识别为规范连续掩码。
只保存 ones 可以吗?
只有在地址族已经由外部字段严格确定时才勉强可行。通用代码应同时保存 bits,否则 IPv4 /24 与其他地址族的同名数字容易被错误比较。
-
502 收藏
-
502 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
363 收藏
-
325 收藏
-
441 收藏
-
453 收藏
-
284 收藏
-
261 收藏
-
418 收藏
-
256 收藏
-
213 收藏
-
406 收藏
-
241 收藏
-
212 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习