为什么同一个IP地址有多种写法
IPv4地址本质上是一个32位的二进制数。计算机只处理这串二进制,各种写法都是为了让不同场景下的人或程序更方便地使用它。
点分十进制:给人看
把32位分成4段,每段8位换算成0~255的十进制数,再用句点连接,就是最常见的192.168.1.1。这种写法便于记忆和口头交流,也是配置路由器、填写DNS时使用的形式。
十进制整数:给程序和数据库用
把4段按位权相加,就得到一个整数:
192×256³ + 168×256² + 1×256 + 1 = 3232235777
用整数保存IP地址只占4个字节,而且可以直接比较大小。判断一个地址是否落在某个地址段内,只需比较它是否介于起止整数之间,IP归属数据库正是按这种方式存储和检索地址段的。MySQL的INET_ATON()和INET_NTOA()函数就用于两种写法之间的转换。
十六进制:抓包与底层排障
十六进制每2位正好对应一段,抓包工具、内存转储和部分系统文件会用这种写法。例如192.168.1.1写作C0A80101。需要注意字节序:Linux的/proc/net/tcp按主机字节序输出,在常见的x86机器上顺序是反的,0101A8C0才对应192.168.1.1。
二进制:理解子网掩码
子网划分是按二进制位进行的。255.255.255.0写成二进制是24个1后接8个0,所以对应/24。网络地址就是IP地址与子网掩码逐位“与”运算的结果。具体计算可以使用子网计算器。
非常规写法的安全隐患
许多系统的地址解析函数(例如C语言的inet_aton)除了点分十进制,还接受整数、十六进制、省略段甚至八进制写法。http://3232235777/、127.1和0177.0.0.1在不少环境中都会被解析成有效地址,后两者都指向127.0.0.1。
如果程序只用字符串规则过滤内网地址,攻击者就可能用这些写法绕过检查,这是服务端请求伪造(SSRF)中的常见手法。正确的做法是先把输入解析成整数,再按地址段判断。本工具为了避免歧义,不接受带前导零的分段。
IPv6的完整写法与压缩写法
IPv6地址有128位,写成8组、每组4位十六进制数。完整写法很长,因此允许压缩,但同一个地址可能出现多种压缩结果。RFC 5952规定了推荐的标准形式:
- 每组去掉前导零,例如
0db8写作db8。 - 用“::”替换最长的一段连续全零分组,且只能出现一次;长度相同时替换第一段。
- 只有一组全零时不使用“::”,直接写作0。
- 字母一律小写。
在日志检索、防火墙规则或数据库比对中,应先把地址统一成同一种形式,否则同一个地址可能因为写法不同而匹配失败。
| 写法 | 是否标准 |
|---|---|
| 2001:0db8:0000:0000:0000:ff00:0042:8329 | 完整写法 |
| 2001:db8:0:0:0:ff00:42:8329 | 去掉前导零,未压缩 |
| 2001:DB8::FF00:42:8329 | 不标准:字母应小写 |
| 2001:db8::ff00:42:8329 | 标准压缩形式 |
相关工具
-
子网计算器
计算网络地址、广播地址、通配符掩码与可用主机数。
-
IP地址与域名归属查询
查询地址的归属地、运营商与ASN。