Python 3:从CIDR表示法创建可能的IP地址列表

31

我被交付任务,在Python(3.1)中创建一个函数,该函数将接收CIDR表示法并返回可能的IP地址列表。我在python.org上进行了搜索,并找到了以下内容:http://docs.python.org/dev/py3k/library/ipaddr.html

但是我没有看到任何可以满足这个需求的东西......如果有人能提供任何帮助,我将非常感激。先行致谢。:-)


6
如果这些答案对您有帮助的话,您可能需要返回并接受一些问题的答案... - TM.
我曾在Python 2.x上使用过IPy(http://c0re.23.nu/c0de/IPy/),现在正在将其移植到Python 3。完成后,我会发布一个链接作为答案。 - AJ.
@AJ:IPy也是一个不错的选择,但我更推荐netaddr,因为我更喜欢它。 :) - jathanism
更新:我已经向IPy的现任维护者提交了一个新版本进行审核。鉴于节假日,我不确定这将何时发布,但一旦发布我会发布链接。 - AJ.
8个回答

74

在Python 3中就这么简单

>>> import ipaddress
>>> [str(ip) for ip in ipaddress.IPv4Network('192.0.2.0/28')]
['192.0.2.0', '192.0.2.1', '192.0.2.2',
'192.0.2.3', '192.0.2.4', '192.0.2.5',
'192.0.2.6', '192.0.2.7', '192.0.2.8',
'192.0.2.9', '192.0.2.10', '192.0.2.11',
'192.0.2.12', '192.0.2.13', '192.0.2.14',
'192.0.2.15']

1
这在Python3终端上可以直接运行,但在.py文件中怎么样? - Tony
@Tony 这个答案的前两行可以放入一个.py文件中,去掉每行开头的>>>。在第二行中,您应该将列表分配给一个变量,然后可以查看或执行其他操作。如果将 [str(ip) for ip in ipaddress.IPv4Network('192.0.2.0/28')] 直接放入文件中运行,将不会有任何输出。但是,将其分配给一个变量,例如ip_list = [str(ip) for ip in ipaddress.IPv4Network('192.0.2.0/28')],然后您可以打印ip_list来查看列表。 - CptSupermrkt
3
请注意,此答案提供的地址列表包括网络地址(192.0.2.0)和广播地址(192.0.2.15),这些地址不能用于分配给主机。这是Python的正确行为,但如果其他利益相关者不熟悉网络,则可能会导致混淆。 - iLoveTux

51
如果你不一定要使用内置的模块,有一个名为netaddr的项目是我用来处理IP网络的最佳模块。请查看IP教程,它说明了处理网络和识别IP地址有多容易。以下是简单示例:
>>> from netaddr import IPNetwork
>>> for ip in IPNetwork('192.0.2.0/23'):
...    print '%s' % ip
...
192.0.2.0
192.0.2.1
192.0.2.2
192.0.2.3
...
192.0.3.252
192.0.3.253
192.0.3.254
192.0.3.255

有趣,但是映射是如何完成的?是否存在一种确定性公式将CIDR网络映射到单个IP地址?还是需要一个数据库来完成映射? - ℕʘʘḆḽḘ

14

我宁愿做一点数学,也不想安装一个外部模块,难道没有跟我一样的人吗?

#!/usr/bin/env python
# python cidr.py 192.168.1.1/24

import sys, struct, socket

(ip, cidr) = sys.argv[1].split('/')
cidr = int(cidr) 
host_bits = 32 - cidr
i = struct.unpack('>I', socket.inet_aton(ip))[0] # note the endianness
start = (i >> host_bits) << host_bits # clear the host bits
end = start | ((1 << host_bits) - 1)

# excludes the first and last address in the subnet
for i in range(start, end):
    print(socket.inet_ntoa(struct.pack('>I',i)))

1
请注意,这不包括广播地址,这可能是您想要的,也可能不是。在计算“end”时,请删除“-1”以包含它。 - Peter
@Peter,仅删除“-1”仅适用于偶数IP地址(例如,第4个八位组以偶数结尾的地址)。在减去1后的行下面添加“end += 1”。 - rabidang3ls
1
@jfky,你能解释一下这个数学问题吗? - drjackild

3

你是否查看过iptools?它似乎非常适合。


鉴于它似乎不支持Python 2.3,要支持Python 3.1可能至少需要一些努力。 - ephemient
2
我已经更新了iptools来支持Python 2.3、2.5、2.6和3.1。 - bd808

2
如果您不想与Python逻辑打交道,可以使用Python的ipaddress库来获得这个。否则,上述解决方案已足够。
import ipaddress
  
def get_ip_from_subnet(ip_subnet):

    ips= ipaddress.ip_network(ip_subnet)
    ip_list=[str(ip) for ip in ips]
    return ip_list

ip_subnet= "192.168.2.0/24"
print(get_ip_from_subnet(ip_subnet))

1

虽然文档中没有提到,但浏览源代码可以发现ipaddr实现了__iter__iterhosts,这正是您所需要的。


哦,没事了。

  1. 看起来 ipaddr.py 在 3.1 beta 版本中被添加到标准库中,但在 3.1 rc 版本中被删除了。
  2. 我正在查看来自原始 ipaddr.py 的源代码,它似乎与 python.org 上的副本分开发展。

你可以只打包后者。


0
以下代码将根据提供的IP和子网掩码生成IP范围。扩展CIDR表示法,例如(255.255.255.0)。
from netaddr import *

def getFirstIp(ipAddress,subnet):
  ipBin = IPNetwork(ipAddress).ip.bits().split('.')
  subBin = IPNetwork(subnet).ip.bits().split('.')
  zipped = zip(ipBin,subBin)
  netIdList = []
  for octets in zipped:
    netIdList.append(''.join(str(b) for b in (map((lambda x: int(x[0])*int(x[1])),zip(list(octets[0]),list(octets[1]))))))
  firstIp = ''
  firstIp = '.'.join(str(int(oct,2)) for oct in netIdList)
  return firstIp


def getLastIp(ipAddress,subnet):
  ipBin = IPNetwork(ipAddress).ip.bits().split('.')
  subBin = IPNetwork(subnet).ip.bits().split('.')
  #print ipBin
  #print subBin
  revsubBin = []
  for octets in subBin:
    revB = ''.join('1' if(b == '0') else '0' for b in octets)
    revsubBin.append(revB)
  zipped = zip(ipBin,revsubBin)
  netIdList = []
  for octets in zipped:
    netIdList.append(''.join(str(b) for b in (map((lambda x: 0 if(int(x[0]) == 0 and int(x[1]) == 0) else 1),zip(list(octets[0]),list(octets[1]))))))
  #print netIdList
  lastIp = ''
  lastIp = '.'.join(str(int(oct,2)) for oct in netIdList)
  return lastIp

def getRangeOfIps(firstIp,lastIp):
  start= int(IPAddress(firstIp))
  end = int(IPAddress(lastIp))
  ipList = []
  for ip in range(start,end+1):
    ipList.append(str(IPAddress(ip)))
  return ipList

def manipulateIP():
 firstIp = getFirstIp(ipAddress,subnet)
 lastIp = getLastIp(ipAddress,subnet)
 ipList = getRangeOfIps(firstIp,lastIp)  
 print ipList 

-3

给定CIDR,生成所有公共IP地址

https://github.com/stephenlb/geo-ip会生成一个包括地理位置在内的有效公共IP地址列表。

'1.0.0.0/8''191.0.0.0/8'是有效的公共IP地址范围,不包括保留的私有IP地址。

IP生成器

生成IP地址和相关地理信息的JSON转储。请注意,有效的公共IP地址范围从'1.0.0.0/8''191.0.0.0/8',不包括下面自述中显示的保留的私有IP地址范围。

docker build -t geo-ip .
docker run -e IPRANGE='54.0.0.0/30' geo-ip               ## a few IPs
docker run -e IPRANGE='54.0.0.0/26' geo-ip               ## a few more IPs
docker run -e IPRANGE='54.0.0.0/16' geo-ip               ## a lot more IPs
docker run -e IPRANGE='0.0.0.0/0'   geo-ip               ## ALL IPs ( slooooowwwwww )
docker run -e IPRANGE='0.0.0.0/0'   geo-ip > geo-ip.json ## ALL IPs saved to JSON File
docker run geo-ip 

扫描所有有效公共地址的更快选项:

for i in $(seq 1 191); do \
    docker run -e IPRANGE="$i.0.0.0/8" geo-ip; \
    sleep 1; \ 
done

这将少于4,228,250,625个JSON行打印到STDOUT。以下是其中一行的示例:

{"city": "Palo Alto", "ip": "0.0.0.0", "longitude": -122.1274,
 "continent": "North America", "continent_code": "NA",
 "state": "California", "country": "United States", "latitude": 37.418,
 "iso_code": "US", "state_code": "CA", "aso": "PubNub",
 "asn": "11404", "zip_code": "94107"}

私有和保留IP范围

上述存储库中的dockerfile将根据维基百科文章的指南排除不可用的IP地址: https://en.wikipedia.org/wiki/Reserved_IP_addresses

MaxMind Geo IP

该dockerfile导入了由https://www.maxmind.com/en/home提供的免费公共数据库。


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