NetCalcLab

IP 转十进制

把 IPv4 地址转换为 32 位无符号十进制整数。地理位置数据库、防火墙引擎与日志分析系统内部正是以这种形式保存地址。

请输入点分十进制地址。

示例:

地址本来就是一个数

点分十进制只是一种呈现格式,并不是底层数据本身。IPv4 地址一直都是一个 32 位整数 —— 点号只是每八位插进去的,方便人类阅读。转成十进制,无非是把这层呈现去掉。

加权求和
十进制 = a × 256³ + b × 256² + c × 256¹ + d × 256⁰
       = a × 16,777,216 + b × 65,536 + c × 256 + d

192.168.1.1 -> 192 × 16,777,216 = 3,221,225,472
               168 ×     65,536 =    11,010,048
                 1 ×        256 =           256
                 1 ×          1 =             1
                                  -----------
                                  3,232,235,777

256 的幂来自字节的长度:把一个字节左移一位,其值就乘以 256 —— 正如把一个十进制数字左移一位就乘以 10。

为什么这个转换并不总是安全

整数形式很方便,但用什么类型来存它影响极大。从 128.0.0.0 起的地址最高位为 1,而有符号 32 位整数会把这一位当作符号位。所以只要类型选错,半个 IPv4 地址空间都会变成负数。

示例:有符号整数引发的问题

192.168.1.1 的最高位是 1,所以有符号 32 位整数会把它存成 3,232,235,777 − 4,294,967,296 = -1,061,515,519。把结果存进有符号 int 字段、再与一个正常数比较的代码,会静默地匹配不上;而同样的代码在 128.0.0.0 以下的地址上却完全正常 —— 这正是这类缺陷常常能通过 10.x 私网测试的原因。

JavaScript 还有一个相关的坑:所有位运算符都会把操作数强制转成有符号 32 位整数。修法是用 >>> 0 把结果归一化为无符号。本站引擎在处理每一个 IPv4 结果时做的正是这件事。

十进制地址会出现在哪些地方

  • 地理位置与 WHOIS 接口。经典的 GeoIP 数据库以整数区间为索引,所以把地址转成整数形式往往是查询的第一步。
  • 服务器日志与分析系统。很多高吞吐日志流水线把地址存成整数,以缩小索引并加快区间扫描。
  • 防火墙与 ACL 引擎。用整数区间表达的规则会编译成几次数值比较,而不是一组字符串模式匹配。
  • 浏览器与 HTML。已废弃的 URL host 形式接受纯十进制写法,所以 http://3232235777/ 会解析到 192.168.1.1。某些客户端至今仍支持,这也是已知的绕过过滤手法。

常见错误

  • 使用有符号 32 位类型。半个地址空间会显示为负数,比较与区间查询随之失效。
  • 把字节权重写反。第一个字节的权重是 256³,不是 256⁰。写反会让每个地址都得到一个一致但错误的数。
  • 用 1000 而不是 256 去乘。把点分形式当成普通十进制数位处理,会丢掉字节对齐,得到的值根本不是一个 IPv4 地址。
  • 忘了最大值是 4,294,967,295。超过这个值,说明它不是 IPv4 地址,而是 IPv6 地址或者出错了。

另见: 十进制转 IP · IP 转二进制 · IP 转十六进制 · 十六进制转 IP · 二进制转 IP

参考:地址与整数对照

常见 IPv4 地址及其十进制与十六进制值
地址十进制十六进制说明
0.0.0.0000000000最小可能值
0.0.0.1100000001次小值
1.1.1.116,843,00901010101十六进制形式为重复模式
8.8.8.8134,744,07208080808公共 DNS 解析器
10.0.0.0167,772,1600A000000RFC 1918 的 10/8 起点
10.0.0.1167,772,1610A00000110/8 中的第一个主机
127.0.0.12,130,706,4337F000001环回地址
172.16.0.02,886,729,728AC100000RFC 1918 的 172.16/12 起点
192.168.0.03,232,235,520C0A80000RFC 1918 的 192.168/16 起点
192.168.1.13,232,235,777C0A80101常见家庭网关
223.255.255.2553,758,096,383DFFFFFFF单播地址范围上界
224.0.0.03,758,096,384E0000000组播地址起点
255.255.255.2554,294,967,295FFFFFFFF最大可能值

私有地址段同样是连续的整数区间:10.0.0.0/8 是 167,772,160 到 184,549,375,192.168.0.0/16 是 3,232,235,520 到 3,232,301,055。大多数数据库的地址分类,就是拿这两个数字做区间判断。

反向转换:十进制转 IP。相关:IP 转二进制、IP 转十六进制、完整 IP 转换器。

常见问题

如何把 IP 地址转成十进制数?

把 32 位当成一个无符号二进制数整体求值。以 192.168.1.1 为例,等于 192 × 16,777,216 + 168 × 65,536 + 1 × 256 + 1 = 3,232,235,777。每个字节按其位置乘以 256 的幂。

为什么权重是 16,777,216 和 65,536?

因为每个字节是八位,一个字节左移一位相当于整体左移八位,也就是乘以 2^8 = 256。所以权重分别是:第一个字节 256^3 = 16,777,216,第二个 256^2 = 65,536,第三个 256,第四个 1。

十进制 IPv4 值的最大值是多少?

4,294,967,295,对应 255.255.255.255。它是 2^32 − 1,也是 32 位无符号位能容纳的最大值。任何大于它的十进制值都不可能是 IPv4 地址。

数据库为什么把 IP 地址存成整数?

整数只占四个字节,而不是最多 15 个字符;比较变成单条机器指令而不是字符串比较;区间查询也退化成 BETWEEN start AND end。排序在数值上也才是正确的 —— 按字符串排序时,10.0.0.1 会排在 9.0.0.1 之前。

为什么我的转换结果是负数?

因为代码用了有符号 32 位整数。从 128.0.0.0 起的地址最高位是 1,在有符号类型里这一位代表负数。有符号 int 会把 192.168.1.1 显示成 -1,061,515,519 而不是 3,232,235,777。改用无符号类型或 64 位整数,问题就消失了 —— 本转换器全程使用无符号运算。

怎么把十进制值转回地址?

先除以 16,777,216 取整得到第一个字节,再用 65,536、256、1 依次处理剩余的余数。十进制转 IP 页面会自动完成这一过程并逐个列出字节。