如何在Python中检查IP是否在网络中?
给定一个 IP 地址(例如 192.168.0.1),如何在 Python 中检查它是否在网络中(例如 192.168.0.0/24)?
Python 中有用于 ip 地址操作的通用工具吗? 像主机查找、IP 地址转为 int、网络地址和网络掩码转为 int 之类的东西? 希望在 2.5 的标准 Python 库中。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
使用 IP 地址 (自 3.3 起的 stdlib,位于PyPi for 2.6/2.7):
如果您想以这种方式评估很多的IP地址,您可能需要预先计算网络掩码,例如
然后,对于每个地址,计算最后
,您可以简单地检查:
Using ipaddress (in the stdlib since 3.3, at PyPi for 2.6/2.7):
If you want to evaluate a lot of IP addresses this way, you'll probably want to calculate the netmask upfront, like
Then, for each address, calculate the binary representation with one of
Finally, you can simply check:
我喜欢使用 netaddr :
正如 arno_v 在评论中指出的那样,新版本的 netaddr 确实像这样:
I like to use netaddr for that:
As arno_v pointed out in the comments, new version of netaddr does it like this:
对于 python3
输出:
For python3
Output :
使用Python >= 3.7 ipaddress:
解释
你可以想到一个 IP 地址 作为具有最大可能网络掩码的网络(对于 IPv4,
/32
;对于 IPv6,/128
)检查是否
192.168.0.1
位于192.168.0.0/16
本质上与检查192.168.0.1/32
是否是192.168 的子网相同。 0.0/16
Using Python >= 3.7 ipaddress:
Explanation
You can think of an IP Address as a Network with the largest possible netmask (
/32
for IPv4,/128
for IPv6)Checking whether
192.168.0.1
is in192.168.0.0/16
is essentially the same as checking whether192.168.0.1/32
is a subnet of192.168.0.0/16
这篇文章表明您可以使用
socket
和struct
模块,无需太多额外的工作。 我在文章中添加了一些内容,如下所示:此输出:
如果您只想要一个接受字符串的函数,则它看起来像这样:
This article shows you can do it with
socket
andstruct
modules without too much extra effort. I added a little to the article as follows:This outputs:
If you just want a single function that takes strings it would look like this:
这段代码在 Linux x86 上适用于我。 我并没有真正考虑过字节序问题,但我已经使用超过 200K IP 地址针对 8 个不同的网络字符串测试了“ipaddr”模块,并且 ipaddr 的结果与此代码相同。
例子:
This code is working for me on Linux x86. I haven't really given any thought to endianess issues, but I have tested it against the "ipaddr" module using over 200K IP addresses tested against 8 different network strings, and the results of ipaddr are the same as this code.
Example:
只要有可能,我都会推荐内置的 ipaddress 模块。 虽然它仅在 Python 3 中可用,但它非常易于使用,并且支持 IPv6。 为什么你还不使用 Python 3,对?
接受的答案不起作用......这让我很生气。 掩码是向后的,并且不适用于非简单 8 位块(例如 /24)的任何位。 我修改了答案,效果很好。
这是一个返回点分二进制字符串的函数,以帮助可视化屏蔽......有点像 ipcalc 输出。
例如:
Wherever possible I'd recommend the built in ipaddress module. It's only available in Python 3 though, but it is super easy to use, and supports IPv6. And why aren't you using Python 3 yet anyway, right?
The accepted answer doesn't work ... which is making me angry. Mask is backwards and doesn't work with any bits that are not a simple 8 bit block (eg /24). I adapted the answer, and it works nicely.
here is a function that returns a dotted binary string to help visualize the masking.. kind of like
ipcalc
output.eg:
我不喜欢在不需要的时候使用模块。 这项工作只需要简单的数学,所以这是我完成这项工作的简单函数:
然后使用它:
就是这样,这比上面包含模块的解决方案要快得多。
I'm not a fan of using modules when they are not needed. This job only requires simple math, so here is my simple function to do the job:
Then to use it:
That's it, this is much faster than the solutions above with the included modules.
2.5 的标准库中没有,但 ipaddr 使这变得非常容易。 我相信它在 3.3 中名为 ipaddress。
Not in the Standard library for 2.5, but ipaddr makes this very easy. I believe it is in 3.3 under the name ipaddress.
我尝试了 Dave Webb 的解决方案,但遇到了一些问题:
最根本的是 - 应该通过将 IP 地址与掩码进行 AND 运算来检查匹配,然后检查结果是否与网络地址完全匹配。 没有像以前那样将 IP 地址与网络地址进行 AND 运算。
我还注意到,仅仅忽略 Endian 行为(假设一致性可以拯救您)将只适用于八位字节边界(/24、/16)上的掩码。 为了让其他掩码(/23、/21)正常工作,我在结构命令中添加了“大于”,并将用于创建二进制掩码的代码更改为以全“1”开头并向左移动(32-mask )。
最后,我添加了一个简单的检查,以确保网络地址对于掩码有效,如果无效则打印警告。
结果如下:
I tried Dave Webb's solution but hit some problems:
Most fundamentally - a match should be checked by ANDing the IP address with the mask, then checking the result matched the Network address exactly. Not ANDing the IP address with the Network address as was done.
I also noticed that just ignoring the Endian behaviour assuming that consistency will save you will only work for masks on octet boundaries (/24, /16). In order to get other masks (/23, /21) working correctly I added a "greater than" to the struct commands and changed the code for creating the binary mask to start with all "1" and shift left by (32-mask).
Finally, I added a simple check that the network address is valid for the mask and just print a warning if it is not.
Here's the result:
从 Python 3.7 开始,您可以使用
subnet_of
和docs.python.org/3/library/ipaddress.html#ipaddress.IPv4Network.supernet_of" rel="noreferrer">
supernet_of
辅助方法,它们 只需针对单个 IP 进行测试,您可以使用子网掩码/32
,这意味着“仅此 IP 地址”作为子网,或者您可以将 IP 地址传递给IPv4Nework
或IPv6Nework
构造函数,它们将为您返回一个子网值。所以对于你的例子:
在 Python 3 中,有一个
ipaddress
模块,其中包含IPv4 和 IPv6 操作工具。 您可以通过强制转换将它们转换为 int,即int(IPv4Address('192.168.0.1'))
。 主机的ipaddress
模块中还有许多其他有用的函数等。As of Python 3.7, you can use
subnet_of
andsupernet_of
helper methods, which are part of the standard library:To just test against a single IP, you can just use the subnet mask
/32
which means "only this IP address" as a subnet, or you can pass the IP address toIPv4Nework
orIPv6Nework
constructors and they will return a subnet value for you.So for your example:
In Python 3, there's the
ipaddress
module which has tools for IPv4 and IPv6 manipulation. You can convert them to an int, by casting, i.e.int(IPv4Address('192.168.0.1'))
. Lots of other useful functions in theipaddress
module for hosts, etc.马克的代码几乎是正确的。 代码的完整版本是 -
显然来自与上面相同的来源...
一个非常重要的注意事项是第一个代码有一个小故障 - IP 地址 255.255.255.255 也显示为任何子网的有效 IP。 我花了很多时间让这段代码正常工作,感谢 Marc 提供的正确答案。
Marc's code is nearly correct. A complete version of the code is -
Obviously from the same sources as above...
A very Important note is that the first code has a small glitch - The IP address 255.255.255.255 also shows up as a Valid IP for any subnet. I had a heck of time getting this code to work and thanks to Marc for the correct answer.
依赖“struct”模块可能会导致字节序和类型大小问题,但这是不必要的。 socket.inet_aton() 也不是。 Python 与点分四组 IP 地址配合得非常好:
我需要针对一整套允许的源网络对每个套接字accept() 调用进行 IP 匹配,因此我预先计算掩码和网络,作为整数:
然后我可以快速查看是否给定的 IP 在这些网络之一内:
不需要导入模块,并且代码的匹配速度非常。
Relying on the "struct" module can cause problems with endian-ness and type sizes, and just isn't needed. Nor is socket.inet_aton(). Python works very well with dotted-quad IP addresses:
I need to do IP matching on each socket accept() call, against a whole set of allowable source networks, so I precompute masks and networks, as integers:
Then I can quickly see if a given IP is within one of those networks:
No module imports needed, and the code is very fast at matching.
所选答案有错误。
以下是正确的代码:
注意:
ipaddr & 网络掩码==网络地址& netmask
而不是ipaddr & 网络掩码==网络掩码
。我还将
((2L< 替换为
((1L << int(bits)) - 1)
,因为后者似乎更容易理解。The choosen answer has a bug.
Following is the correct code:
Note:
ipaddr & netmask == netaddr & netmask
instead ofipaddr & netmask == netmask
.I also replace
((2L<<int(bits)-1) - 1)
with((1L << int(bits)) - 1)
, as the latter seems more understandable.from netaddr import all_matching_cidrs
以下是此方法的用法:
基本上,您提供一个 ip 地址作为第一个参数,并提供一个 cidrs 列表作为第二个参数。 返回命中列表。
from netaddr import all_matching_cidrs
Here is the usage for this method:
Basically you provide an ip address as the first argument and a list of cidrs as the second argument. A list of hits are returned.
之前的解决方案在 ip & 方面存在错误。 净==净。 正确的 ip 查找是 ip & netmask = net
修正代码:
previous solution have a bug in ip & net == net. Correct ip lookup is ip & netmask = net
bugfixed code:
这是我为最长前缀匹配编写的一个类:
这是一个测试程序:
Here is a class I wrote for longest prefix matching:
And here is a test program:
感谢您的脚本!
我花了很长时间才让一切正常工作...所以我在这里分享它
makeMask函数不起作用! 仅适用于 /8、/16、/24
例如:
<块引用>
位=“21”; socket.inet_ntoa(struct.pack('=L',(2L << int(位)-1) - 1))
“255.255.31.0”,而它应该是 255.255.248.0
所以我使用了 http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/
例如:
例如:暂时,该函数是错误的
所以我的新 addressInNetwork 函数看起来像:
现在,答案是正确的! !
我希望它能帮助其他人,为他们节省时间!
Thank you for your script!
I have work quite a long on it to make everything working... So I'm sharing it here
makeMask function is not working! Only working for /8,/16,/24
Ex:
So I have used another function calcDottedNetmask(mask) from http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/
Ex:
Ex: for the time being, the function is wrong
So my new addressInNetwork function looks-like:
And now, answer is right!!
I hope that it will help other people, saving time for them!
与上述所有内容相关,我认为 socket.inet_aton() 按网络顺序返回字节,因此解压它们的正确方法可能是
Relating to all of the above, I think socket.inet_aton() returns bytes in network order, so the correct way to unpack them is probably
$ python check-subnet.py
错误
真实
错误的
$ python check-subnet.py
False
True
False
从上面的各种来源以及我自己的研究来看,这就是我如何进行子网和地址计算的。 这些部分足以解决这个问题和其他相关问题。
From various sources above, and from my own research, this is how I got subnet and address calculation working. These pieces are enough to solve the question and other related questions.
Python 中有一个名为 SubnetTree 的 API 可以很好地完成这项工作。
这是一个简单的示例:
这是链接
There is an API that's called SubnetTree available in python that do this job very well.
This is a simple example :
This is the link
这是我的代码
Here is my code
如果您不想导入其他模块,您可以使用:
If you do not want to import other modules you could go with:
我尝试了这些答案中建议的解决方案的一个子集..但没有成功,我最终调整并修复了建议的代码并编写了我的固定函数。
我测试了它并且至少可以在小端架构上工作——例如x86——如果有人喜欢尝试大端架构,请给我反馈。
IP2Int
代码来自这篇文章,另一种方法是完全的(对于我的测试用例)该问题之前提案的工作修复。代码:
希望有用,
I tried one subset of proposed solutions in these answers.. with no success, I finally adapted and fixed the proposed code and wrote my fixed function.
I tested it and works at least on little endian architectures--e.g.x86-- if anyone likes to try on a big endian architecture, please give me feedback.
IP2Int
code comes from this post, the other method is a fully (for my test cases) working fix of previous proposals in this question.The code:
Hope useful,
这是使用 netaddr 包的解决方案
Here is the solution using netaddr package
为了避免内置或第三方模块随着时间的推移改变其语法,我创建了自己的模块来执行此操作。 我将其用作可导入模块。 我希望这可以帮助别人:
To avoid having builtin or third party modules change their syntax over time, I created my own that does this. I'm using this as an importable module. I hope this helps someone:
此函数检查 IP 地址是否属于私有 IP 子网或公共子网域。
This function checks if IP Address falls in Private IP Subnet or Public Subnet Domain.
另一种解决方案是使用
IPy
库The other solution is to use
IPy
library