仅匹配公共IPv4地址的正则表达式

4

一开始,我以为在互联网上找到只匹配公共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}|
...

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

https://metacpan.org/pod/Regexp::Common::net#RE-net-IPv4 可以匹配 IPv4 地址。我不会将“公共”检查放入正则表达式中。 - melpomene
你在尝试做什么?127\.\d{1,3}\.\d{1,3}\.\d{1,3}并不是公共的!! - Abr001am
@chris85 你只是检查了私有IP地址,而不是公共IP地址。 - Matt Elson
@chris85 我正在使用一个编辑器进行搜索,而不是一种语言。 - Matt Elson
可能是使用正则表达式验证IPv4地址的重复问题。 - jww
显示剩余5条评论
5个回答

12

试试这个:

^([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])$

它正确地不匹配这些无效的IP地址:

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到169.254.255.255 = 169.254.0.0/16 怎么样了?https://regex101.com/r/GWcMlF/1 - qräbnö
实际上,它们是 169.254.1.1 到 169.254.254.255,这给这个快速粗糙的 IPv4 地址验证带来了不必要的复杂性。一个明显的方法是在 (?<!192.168) 块后面加上 (?<!169.254),就像你在 regex101 链接中提到的那样,这样就可以不排除第一个和最后一个 256 个地址进行验证了。 - Anubioz
第一个有用的是169.254.0.1。最后一个有用的是169.254.255.254 - 如果我没记错的话。除此之外,我同意。顺便问一下:真的有必要两次这样做吗:(?<!172\.(?:16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31)) - qräbnö
这是错误的... 60.123.247.255 是一个有效的 IP 地址,而不是广播地址。同样,60.123.247.0 也是一个有效的 IP 地址。 - Livio Zanol Puppim
@LivioZanolPuppim 你是完全正确的。 - Anubioz

7
我更愿意在代码中捕获每个八位组并检查子网是否为私有,而不是使用正则表达式。然而,我对你的问题很感兴趣。
根据维基百科,私有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

假设您没有像 55.300.666.1 这样的奇怪 IP 格式,您可以使用负回顾后断言来实现您想要的效果:
(\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。第二行检查前两个八位组是否不是192.168或在172.16172.31之间。第三行没有什么特别之处。Regex101

注:我知道127.0.0.1是本地主机,但我不知道它是否是私有地址(我不是网络工程师)。您可能需要根据需要自行调整。


1
我在Solarwinds中使用了你的正则表达式语句来查找具有公共IP地址的设备。它完美地工作了。谢谢。 - vlmercado
2
整个IP范围从127.0.0.1到127.255.255.255都不被视为“公共IP地址”,因此不应与公共IP范围匹配。 - Thomas Ward
这是一个临时的第一行代码,用于不匹配本地主机:(\d+)(?<!10)(?<!127) - nakakapagpabagabag

5
如果您想验证纯公共IPv4地址,我们可以通过以下方式消除所有保留的IPv4地址
  • 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:广播

(列表摘自维基百科


这可以成为一个简单的正则表达式,不使用回溯(因此,该正则表达式可以在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地址怎么样?https://regex101.com/r/wxULXv/1 - qräbnö
60.123.247.255是一个有效的IP地址,不是广播地址。同样,60.123.247.0也是有效的。 - Livio Zanol Puppim

2
 ^([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,根据需要添加或删除。


1
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://istack.dev59.com/vWtlj.webp

(不广播)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接