【问题标题】:Regex to ONLY match PUBLIC IPv4 address正则表达式仅匹配公共 IPv4 地址
【发布时间】:2016-01-31 21:16:39
【问题描述】:

起初,我认为在 Internet 上找到仅匹配公共 IPv4 地址的正则表达式很容易。然而,经过大量的谷歌搜索,我什么也没得到,所以我尝试 编写正则表达式,如下(Perl 风格),

[0-9]\.(?:[0-9]{1,3}\.){2}[0-9]{1,3}|
1[1-9]\.(?:[0-9]{1,3}\.){2}[0-9]{1,3}|
[2-9][0-9]\.(?:[0-9]{1,3}\.){2}[0-9]{1,3}|
1[0-6][0-9]\.(?:[0-9]{1,3}\.){2}[0-9]{1,3}|
17[0-1]\.(?:[0-9]{1,3}\.){2}[0-9]{1,3}|
172\.0\.(?:[0-9]{1,3}\.)[0-9]{1,3}|
172\.1[0-5]\.(?:[0-9]{1,3}\.)[0-9]{1,3}|
(172\.3[2-9]\.)(?:[0-9]{1,3}\.)[0-9]{1,3}|
(172\.[4-9][0-9]\.)(?:[0-9]{1,3}\.)[0-9]{1,3}|
...

正则表达式似乎不准确且效率低下,有人有更好的方法来编写正则表达式吗?

【问题讨论】:

  • metacpan.org/pod/Regexp::Common::net#RE-net-IPv4 将匹配 IPv4 地址。我不会将“公共”检查放入正则表达式中。
  • 你想做什么? 127\.\d{1,3}\.\d{1,3}\.\d{1,3}不公开!!
  • 我已经通过.s 断开了字符串,然后检查了过去if (($sections[0] == 192 && $sections[1] == 168) || ($sections[0] == 172 && ($sections[1] >= 16 && $sections[1] <= 32)) || ($sections[0] == 10)) { 中的每个值。你用什么语言运行这个? (还有那个条件是检查你的请求的逆;如果匹配它就是私有的)。
  • @chris85 你只检查私有 IP 地址,而不是公共 IP 地址。
  • 是的,反过来,你使用的语言不支持else?

标签: regex


【解决方案1】:

试试这个:

^([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(?<!172\.(16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31))(?<!127)(?<!^10)(?<!^0)\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(?<!192\.168)(?<!172\.(16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31))\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$

它正确地不匹配这个无效的ips:

999.999.999.999.
108.0.0.01
0.1.2.3
00.0000.00.00
192.168.l.1
912.456.123.123
.3.3.3.0
192.168.o.0

不匹配本地 IP:

172.16.0.9
172.16.4.1
172.17.1.1
127.0.0.2
10.0.1.5
10.0.0.1
10.155.155.155
10.255.255.254
172.16.0.4
172.16.0.1
172.17.1.1
172.31.254.254
192.168.1.2
192.168.254.0

并且几乎匹配我测试过的每个 IP。不能说我真的做了很多测试,所以欢迎提出建议

【讨论】:

  • 自 2005 年以来的私有链接本地地址 169.254.0.0 to 169.254.255.255 = 169.254.0.0/16 怎么样? regex101.com/r/GWcMlF/1
  • 实际上它们是 169.254.1.1 到 169.254.254.255,这给这个快速而肮脏的 ipv4 地址验证带来了不必要的复杂性。如您的 regex101 链接中所述,在不排除第一个和最后 256 个地址的情况下,一种明显的方法是将 (?
  • 第一个有用的是169.254.0.1。最后一个有用的是 169.254.255.254 - IIRC。除此之外,我同意。顺便说一句:真的有必要两次:(?&lt;!172\.(?:16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31))
  • 这是错误的...... 60.123.247.255 是一个有效的 IP 地址,而不是广播。 60.123.247.0 也是如此。
  • @LivioZanolPuppim 你完全正确。
【解决方案2】:

我宁愿捕获每个八位字节并检查子网在代码中是否是私有的,而不是使用正则表达式。不过,我对你的问题很感兴趣。

根据Wikipedia,私有IP地址有3个范围。

10.0.0.0    - 10.255.255.255
172.16.0.0  - 172.31.255.255
192.168.0.0 - 192.168.255.255

现在假设您没有疯狂的类似 IP 的字符串,例如 55.300.666.1,您可以使用否定的lookbehind 来做您想做的事情:

(\d+)(?<!10)\.(\d+)(?<!192\.168)(?<!172\.(1[6-9]|2\d|3[0-1]))\.(\d+)\.(\d+)

让我们再看一遍,为清楚起见添加了一些换行符:

(\d+)(?<!10)
\.(\d+)(?<!192\.168)(?<!172\.(1[6-9]|2\d|3[0-1]))
\.(\d+)\.(\d+)

第一行检查第一个八位字节不是10。第二行检查前 2 个八位字节是否不是 192.168 或介于 172.16172.31 之间。第三行没什么特别的。 Regex101

PS:我知道127.0.0.1 是本地主机,但我不知道它是否是私有的(我不是网络工程师)。您可能需要根据需要即兴发挥。

【讨论】:

  • 我在 Solarwinds 中使用了您的正则表达式语句来查找具有公共 IP 地址的设备。它工作得很好。谢谢。
  • 从 127.0.0.1 到 127.255.255.255 的整个 IP 范围不被视为“公共 IP 地址”,不应与公共 IP 范围匹配。
【解决方案3】:

如果您希望验证纯公共 IPv4 地址,我们可以消除所有 Reserved IPv4 addresses,如下所示:

  • 0.0.0.0/8:当前网络
  • 10.0.0.0/8:私网
  • 100.64.0.0/10:共享地址空间
  • 127.0.0.0/8:环回
  • 169.254.0.0/16: 链接本地
  • 172.16.0.0/12: 私网
  • 192.0.0.0/24:IETF 协议分配
  • 192.0.2.0/24:TEST-NET-1,文档和示例
  • 192.88.99.0/24:IPv6 到 IPv4 中继(包括 2002::/16)
  • 192.168.0.0/16:私网
  • 198.18.0.0/15:网络基准测试
  • 198.51.100.0/24:TEST-NET-2,文档和示例
  • 203.0.113.0/24:TEST-NET-3,文档和示例
  • 224.0.0.0/4:IP 多播(以前的 D 类网络)
  • 240.0.0.0/4:保留(原E类网络)
  • 255.255.255.255:广播

(列表取自Wikipedia


这可以放入一个不使用lookbehinds的简单正则表达式(因此,正则表达式可以在JavaScript中使用):

(^0\.)|(^10\.)|(^100\.6[4-9]\.)|(^100\.[7-9]\d\.)|(^100\.1[0-1]\d\.)|(^100\.12[0-7]\.)|(^127\.)|(^169\.254\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.0\.0\.)|(^192\.0\.2\.)|(^192\.88\.99\.)|(^192\.168\.)|(^198\.1[8-9]\.)|(^198\.51\.100\.)|(^203.0\.113\.)|(^22[4-9]\.)|(^23[0-9]\.)|(^24[0-9]\.)|(^25[0-5]\.)

同样,这假设您已经事先验证它实际上是一个有效的 IPv4 地址。

【讨论】:

  • 广播IP地址呢? regex101.com/r/wxULXv/1
  • 60.123.247.255 是一个有效的 IP 地址,而不是广播。 60.123.247.0 也是如此。
【解决方案4】:
 ^([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(?<!172\.(16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31))(?<!127)(?<!^10)(?<!^0)\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(?<!192\.168)(?<!172\.(16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31))\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(?<!\.255$)(?<!\b255.255.255.0\b)(?<!\b255.255.255.242\b)$

一个稍微不同的解决方案,如果您通过防火墙配置进行 grep,它会删除误报地址。删除常见的掩码 255.255.255.0 和 255.255.255.242。根据需要添加和删除。

【讨论】:

    【解决方案5】:

    Anubioz 的 + Irvin Lim=

    ^(?!^0\.)(?!^10\.)(?!^100\.6[4-9]\.)(?!^100\.[7-9]\d\.)(?!^100\.1[0-1]\d\.)(?!^100\.12[0-7]\.)(?!^127\.)(?!^169\.254\.)(?!^172\.1[6-9]\.)(?!^172\.2[0-9]\.)(?!^172\.3[0-1]\.)(?!^192\.0\.0\.)(?!^192\.0\.2\.)(?!^192\.88\.99\.)(?!^192\.168\.)(?!^198\.1[8-9]\.)(?!^198\.51\.100\.)(?!^203.0\.113\.)(?!^22[4-9]\.)(?!^23[0-9]\.)(?!^24[0-9]\.)(?!^25[0-5]\.)(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))$
    

    https://i.stack.imgur.com/vWtlj.png

    (无广播)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-15
      相关资源
      最近更新 更多