为什么 ping 192.168.072(只有 2 个点)会返回来自 192.168.0.58 的响应?

Geo*_*ett 381 ip-address ping ip

我错误地错过了 IP 地址的点号并输入了192.168.072.
令我惊讶的是,我连接到了一台机器192.168.0.58

如果我 ping192.168.072我会收到来自192.168.0.58.

为什么是这样?


我在 Windows 域中的 Windows PC 上。


如果我 ping192.168.72我会收到来自 的回复192.168.0.72,所以看起来0in 072(在我原来的错误中)很重要。


这个问题是本周超级用户问题
阅读博客条目以了解更多详细信息或自己为博客做出贡献

Syn*_*ech 572

每个人都用 RFC、IP 类等使它过于复杂。只需运行一些测试,即可查看该ping命令如何解析用户输入的 IP(去除了无关的箔条):

> ping 1
Pinging 0.0.0.1 with 32 bytes of data:

> ping 1.2
Pinging 1.0.0.2 with 32 bytes of data:

> ping 1.2.3
Pinging 1.2.0.3 with 32 bytes of data:

> ping 1.2.3.4
Pinging 1.2.3.4 with 32 bytes of data:

> ping 1.2.3.4.5
Ping request could not find host 1.2.3.4.5. Please check the name and try again.

> ping 255
Pinging 0.0.0.255 with 32 bytes of data:

> ping 256
Pinging 0.0.1.0 with 32 bytes of data:
Run Code Online (Sandbox Code Playgroud)

如您所见,该ping命令(在 Windows 中)允许您使用不同的 IP 地址格式。IPv4 地址可以分解为四部分(“dotted-quad”),如下所示:A.B.C.D,该ping命令允许您省略一些,填写0如下默认值:

1 part  (ping A)       : 0.0.0.A
2 parts (ping A.B)     : A.0.0.B
3 parts (ping A.B.C)   : A.B.0.C
4 parts (ping A.B.C.D) : A.B.C.D
Run Code Online (Sandbox Code Playgroud)

如果你只提供一个部分,那么如果它小于 255(一个八位字节的最大值),它会像上面一样被当作八位字节处理,但如果它大于 255,那么它会被转换并滚动到下一个字段(即,mod 256)。

有一些边缘情况,例如提供四个以上的部分似乎不起作用(例如,pinggoogle.com的 IP 对0.74.125.226.4或都不起作用74.125.226.4.0)。

您还可以在点分四进制和平面格式中使用十六进制表示法,但必须通过0x在每个八位位组前面添加来对其进行格式化。


因此,有很多方法可以表示 (IPv4) IP 地址。您可以使用平面或点四(或点三、点双,甚至点单)格式,对于每一种,您都可以使用(甚至混合和匹配)十进制、八进制和十六进制。例如,您可以google.com通过以下方式ping 通:

  • google.com  (域名)
  • 74.125.226.4  (点分十进制)
  • 1249763844  (平面小数)
  • 0112.0175.0342.0004  (虚线八进制)
  • 011237361004  (平八进制)
  • 0x4A.0x7D.0xE2.0x04  (虚线十六进制)
  • 0x4A7DE204  (平面六角)
  • 74.0175.0xe2.4  (?_?)

(谢天谢地,没有添加二进制符号支持!)


应用

在您的情况下,ping192.168.072使用上表 ( A.B.0.C) 中的第三种格式,因此您实际上是在 ping 192.168.0.072。此外,因为最后一部分有一个前导零,所以它被视为八进制,十进制为 58。

谜团已揭开。


请注意,虽然 Windowsping命令允许输入如此广泛的格式并以所见的方式解释非标准格式,但这并不一定意味着您可以在任何地方使用此类格式。有些程序可能会强制您提供点分四进制的所有四个部分,其他程序可能不允许混合和匹配十进制和八进制,等等。

此外,IPv6 地址使解析逻辑和输入格式可接受性进一步复杂化。


附录

syss 指出,如果您在其中一个数字中使用无效字符(例如,当使用八进制时使用an8或,十六进制模式中的9ag等),那么ping足够聪明地识别它并将其解释为字符串(-al? -ic?) URL 而不是数字 IP 地址。

(作为一个患有无数动脉瘤和心脏病的人,试图编写所谓的“简单”代码来适应数据值排列呈指数爆炸的数量,我很欣赏它 - 似乎 - 正确处理所有输入变化;在这个情况下,至少有 3 1 +3 2 +3 3 +3 4 = 120 个变化。)

因此,虽然指定010.020.030.040will ping8.16.24.32按预期,传递010.020.030.080ping将被视为 URL 而不是 IP 地址 - 就像foo.bar.baz.com可能(但遗憾的是不存在)存在一样。换句话说,它尝试在顶级域010的域020上ping 子域上的子030080。但是,由于080不是有效的 TLD(例如.com.net和他们的伙伴),因此连接在第一步就失败了。

同样的事情发生090.010.010.010在无效字符在不同的八位字节中。同样,0xf.0xf.0xf.0xfpings 15.15.15.15,但0xh1.0x1.0xg0.0f失败。

哦,好吧,我想这就是你不精通多种数字基础的结果。

确保始终使用 4-dotted-quad(“40q”?“quaddy-quad”?“cutie-q”?)地址可能更容易也更安全。

所以去学习一些数基。你将能够炫耀并成为派对的生活,正如他们所说,有 10 种人:懂二进制的和不知道二进制的。

我们甚至不用考虑IPv6 地址;我认为他们是 111 封印之一!!!

  • 你看!计算机科学的“科学”部分亮相!(假设、实验、验证) (71认同)
  • 过于复杂?实验非常有用,在这种情况下会产生一个很好的答案;但如果没有理论、文档或标准,您可能会遗漏一个关键因素而不知道它。或者,您可能正在确定一个特定版本的工作方式,并且大约 90% 的实现都是错误的。或者你可以想出一些规则来解释你的实验结果,但比预期的规则更复杂。在这种情况下,我认为文档的规则(对于`inet_aton()`)在一方面更简单——没有“低于/超过 255”的条件。 (39认同)
  • @LarsH,这就是我的观点,`ping` 命令(至少在 Windows 上)就像许多微软的程序(尤其是臭名昭著的)IE。它试图过于宽容并接受你扔给它的任何东西并试图解释它。是的,有一个关于 IP 地址格式的官方文档,但这不是关于 ISO 和 RFC 的问题,它是实用的,*我做了一些事情,这很奇怪*问题无需求助于(诚然冗长,枯燥) ,无聊的技术规范)——尽管链接到它们以防 OP 想要阅读它们也很好。 (13认同)
  • 应该完全放弃以 0 为前缀的八进制解析,除了 `chmod`。就是这样。这是八进制允许的唯一例外。时期。 (6认同)
  • 它对于 RGB HEX 到 DEC 的转换很有用。大声笑~ `C:\>ping 0xffffcc``Ping 0.255.255.204 有 32 个字节的数据:` (6认同)
  • 用 su 写的最好的一行:74.0175.0xe2.226 (ಠ_ಠ) (3认同)
  • @wilson,不错的把戏!它甚至“支持”Alpha 通道。`:-D` (3认同)

neu*_*242 148

有两个原因:

首先,“0”前缀表示八进制数。由于 oct(072) = dec(58),192.168.072 = 192.168.58。

其次,倒数第二个 0 可以作为速记从 IP 地址中删除。127.0.1 被解释为 127.0.0.1,在你的情况下 192.168.58 被解释为 192.168.0.58。

  • 它不会对零进行分组。它实际上将每个点视为对应于下一个字节边界的分隔符。因此,IP 地址 2130706433 和 127.0.0.1 是相同的地址。 (8认同)
  • 著名的前导零再次击中! (4认同)
  • 更准确地说,它是 IP 地址的四点符号 (2认同)
  • 现在这是真正的答案! (2认同)
  • 该答案不正确且具有误导性。在 1.0.2.3 (1.2.3) 中删除 0 会给出不同的 IP 地址 (1.2.0.3)。 (2认同)

Lar*_*rsH 103

除了@neu242 关于八进制表示法的要点以及 IP 地址可以缩短的观察之外,另一个关键部分是了解如何解释缩短的 IP 地址。

人们可能会天真地猜测,如果缺少四个数字中的一些,解析器会在字节序列的末尾(或开头)添加填充零的字节。但这与 OP 报告的行为不符:192.168.072 被解析为 192.168。0 .58,而不是 192.168.58。0,也不是0 .192.168.58。

显然,Windows 和 Linux ping(您尝试过的版本和我尝试过的版本)使用与 inet_aton() 等效的东西来解析 IP 地址参数。inet_aton()手册页说:

The address supplied in cp can have one of the following forms:

 a.b.c.d   Each of the four numeric parts specifies a byte of the address; the
           bytes are assigned in left-to-right order to produce the binary
           address.

 a.b.c     Parts a and b specify the first two bytes of the binary address.
           Part c is interpreted as a 16-bit value that defines the rightmost
           two bytes of the binary address.  This notation is suitable for
           specifying (outmoded) Class B network addresses.

 a.b       Part a specifies the first byte of the binary address.  Part b is
           interpreted as a 24-bit value that defines the rightmost three bytes
           of the binary address.  This notation is suitable for specifying
           (outmoded) Class C network addresses.

 a         The value a is interpreted as a 32-bit value that is stored directly
            into the binary address without any byte rearrangement.
Run Code Online (Sandbox Code Playgroud)

所以你有它......192.168.072符合 abc 模式,所以072(在解析为八进制数之后)被解释为一个 16 位值,它定义了二进制地址的最右边的 2 个字节,相当于0.58.

上述规则相当于说,如果缺少四个数字中的任何一个,则在给定的最后一个数字之前立即添加所需的零填充字节......而不是在字节串的末尾或开头。(如果给出的最后一个数字小于 256,则以这种方式表达它是有效的。)

请注意,较新版本的 ping 可能不允许这种速记,也不允许八进制解释。我发现的iputils(包括 ping)的2010 源代码使用 inet_pton() 而不是 inet_aton() 来解析 IP 地址参数。inet_pton()手册页说:

与 inet_aton(3) 和 inet_addr(3) 不同,inet_pton() 支持 IPv6 地址。另一方面,inet_pton() 只接受点分十进制表示法的 IPv4 地址,而 inet_aton(3) 和 inet_addr(3) 允许更通用的数字和点表示法(十六进制和八进制数字格式,以及不t 需要显式写入所有四个字节)。

  • 恕我直言,这是迄今为止最好的答案。 (12认同)

小智 24

您还必须考虑到,一个 ip 可以由对其位置意义相加的整数表示。

192.168.0.58 is :
  192 * 256^3
+ 168 * 256^2
+   0 * 256^1
+  58 * 256^0
Run Code Online (Sandbox Code Playgroud)

这是很酷的事情:

192.168.58 将是 192.168.0.58 因为

    0 * 256^1 
+  58 * 256^0 
=  58
Run Code Online (Sandbox Code Playgroud)

192.11010106 也将是 192.168.0.58 因为

  168 * 256^2 
+   0 * 256^1 
+  58 * 256^0 
= 11010106
Run Code Online (Sandbox Code Playgroud)

3232235578 也将是 192.168.0.58 因为

  192 * 256^3 
+ 168 * 256^2 
+   0 * 256^1 
+  58 * 256^0 
= 3232235578
Run Code Online (Sandbox Code Playgroud)